# 文件名: app/services/monitor_service.py
import os
import json
import asyncio
import random
import re
import uuid
import datetime
from typing import List

import aiofiles
import aiohttp
import httpx
from sqlalchemy.orm import Session

from app.utils.logging_config import logger
from app.models.database import MonitoredUser, Video, SystemSetting, get_local_time, HotVideo
from app.routes.websocket import send_progress
from app.services.api_service import ApiService
import math


def get_safe_filename(filename):
    # 移除不适合作为文件名的字符
    invalid_chars = r'[<>:"/\\|?*\x00-\x1f]'
    safe_name = re.sub(invalid_chars, '_', filename)
    # 移除前导和尾随空格及点
    safe_name = safe_name.strip('. ')
    # 如果为空，使用默认名称
    if not safe_name:
        safe_name = 'untitled'
    return safe_name


def sanitize_filename(text):
    # 替换 Windows 非法字符（包括空格和感叹号）
    for ch in ['\\', '/', ':', '*', '?', '"', '<', '>', '|', '!', ' ', ' \ ', '\n']:
        text = text.replace(ch, '')
    return text


def extract_tags(text):
    # 提取以 # 开头的标签，包括中文、字母、数字、下划线
    return ''.join(re.findall(r'#\w[\w一-龥]*', text))


def extract_title_prefix(text, max_len=30):
    # 去掉 #及其后内容，截取正文前缀
    content = text.split('#')[0]
    clean_content = sanitize_filename(content)
    return clean_content[:max_len]


def generate_filename(video_title, video_id, dir_path):
    title_prefix = extract_title_prefix(video_title)
    tags = extract_tags(video_title)

    if not title_prefix:
        title_prefix = str(video_id)

    # 拼接文件名
    file_name = f"{title_prefix}_{video_id}{tags}.mp4"
    return os.path.join(dir_path, file_name)


async def download_video_with_urls(db: Session, url_list, file_path, client_id=None):
    """通用方法：从URL列表下载视频到指定路径"""
    # 从系统设置获取配置参数
    try:
        max_retries = int(SystemSetting.get_value(db, "max_retries", "3"))
        retry_delays_str = SystemSetting.get_value(db, "retry_delays", "2,3,4")
        retry_delays = [int(x) for x in retry_delays_str.split(",")]
        timeout = int(SystemSetting.get_value(db, "request_timeout", "180"))
        min_delay = float(SystemSetting.get_value(db, "min_delay", "1.0"))
        max_delay = float(SystemSetting.get_value(db, "max_delay", "3.0"))
    except Exception as e:
        logger.error(f"获取系统设置时出错: {str(e)}，使用默认值")
        max_retries = 3
        retry_delays = [2, 3, 4]
        timeout = 180
        min_delay = 1.0
        max_delay = 3.0

    # 确保retry_delays列表长度与max_retries匹配
    while len(retry_delays) < max_retries:
        retry_delays.append(retry_delays[-1] * 2)

    if not url_list:
        logger.warn("URL列表为空，无法下载")
        return False

    # 随机延迟函数，避免被识别为爬虫
    async def random_delay():
        delay = random.uniform(min_delay, max_delay)
        logger.info(f"添加随机延迟: {delay:.2f}秒")
        await asyncio.sleep(delay)

    success = False
    error_messages = []
    url_index = 0

    for url in url_list:
        url_index += 1
        url_quality = "高清" if url_index <= len(url_list) // 2 else "标清"
        logger.info(f"尝试下载 {url_quality} 视频 (URL {url_index}/{len(url_list)})")

        # 在每个URL尝试前添加随机延迟
        await random_delay()

        for retry in range(max_retries):
            try:
                logger.info(f"尝试从URL下载: {url[:100]}... (尝试 {retry + 1}/{max_retries})")

                # 添加随机User-Agent，模拟不同浏览器
                headers = {
                    'User-Agent': random.choice([
                        'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
                        'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Safari/605.1.15',
                        'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0',
                        'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36'
                    ]),
                    'Accept': 'video/webm,video/mp4,video/*;q=0.9,*/*;q=0.8',
                    'Accept-Language': 'en-US,en;q=0.9',
                    'Accept-Encoding': 'gzip, deflate, br',
                    'Referer': 'https://www.douyin.com/',
                    'Origin': 'https://www.douyin.com',
                    'Connection': 'keep-alive'
                }

                async with aiohttp.ClientSession() as session:
                    async with session.get(url, headers=headers, timeout=timeout) as response:
                        if response.status == 200:
                            content = await response.read()
                            content_length = len(content)

                            if content_length < 1000:  # 检查内容是否太小
                                logger.info(f"下载内容太小 ({content_length} 字节)，可能不是视频文件")
                                error_messages.append(f"内容太小: {content_length} 字节")
                                break  # 内容太小直接尝试下一个URL

                            # 检查内容类型是否为视频
                            content_type = response.headers.get('Content-Type', '')
                            if not ('video' in content_type or 'octet-stream' in content_type):
                                logger.info(f"错误的内容类型: {content_type}，可能不是视频文件")
                                error_messages.append(f"错误的内容类型: {content_type}")
                                break  # 不是视频类型，尝试下一个URL

                            logger.info(f"下载完成，正在保存文件: {file_path}")
                            os.makedirs(os.path.dirname(file_path), exist_ok=True)

                            async with aiofiles.open(file_path, 'wb') as f:
                                await f.write(content)

                            # 检查文件是否写入成功
                            if os.path.exists(file_path) and os.path.getsize(file_path) > 1000:
                                logger.info(f"文件下载成功: {file_path} ({os.path.getsize(file_path)} 字节)")
                                success = True
                                return True  # 下载成功直接返回
                            else:
                                logger.error(f"文件下载失败或文件太小: {file_path}")
                                error_messages.append("文件写入失败或文件太小")
                                # 继续重试
                        else:
                            logger.error(f"HTTP响应错误: {response.status} {response.reason}")
                            error_messages.append(f"HTTP {response.status}: {response.reason}")
                            if retry < max_retries - 1:  # 如果不是最后一次重试
                                wait_time = retry_delays[retry]
                                logger.info(f"等待 {wait_time} 秒后重试...")
                                await asyncio.sleep(wait_time)

            except Exception as e:
                logger.error(f"下载时发生错误: {str(e)} (尝试 {retry + 1}/{max_retries})")
                error_messages.append(f"错误: {str(e)}")
                if retry < max_retries - 1:  # 如果不是最后一次重试
                    wait_time = retry_delays[retry]
                    logger.info(f"等待 {wait_time} 秒后重试...")
                    await asyncio.sleep(wait_time)

    logger.error(f"所有下载尝试都失败: {error_messages}")
    return False


# 辅助函数：提取视频URL及其宽高信息，不考虑方向过滤
def extract_douyin_video_urls_with_info(video_data):
    """
    提取视频URL及其宽高信息，按质量排序但不过滤方向

    参数:
        video_data: 视频数据JSON对象

    返回:
        list: 包含URL和宽高信息的字典列表
    """
    if "video" not in video_data:
        return []

    video_info = video_data["video"]
    all_sources = []

    # 判断视频方向的辅助函数
    def get_orientation(width, height):
        if width > height:
            return "landscape"  # 横屏
        elif height > width:
            return "portrait"  # 竖屏
        else:
            return "square"  # 正方形

    # 处理bit_rate数组中的视频源
    if "bit_rate" in video_info:
        for bit_rate in video_info["bit_rate"]:
            if "play_addr" in bit_rate and "url_list" in bit_rate["play_addr"]:
                width = bit_rate["play_addr"].get("width", 0)
                height = bit_rate["play_addr"].get("height", 0)
                quality_type = bit_rate.get("quality_type", 999)

                for url in bit_rate["play_addr"]["url_list"]:
                    all_sources.append({
                        "url": url,
                        "width": width,
                        "height": height,
                        "quality_type": quality_type,
                        "quality_score": width * height,
                        "orientation": get_orientation(width, height)
                    })

    # 处理主要视频格式
    for format_type in ["play_addr_265"]:
        if format_type in video_info and "url_list" in video_info[format_type]:
            width = video_info[format_type].get("width", 0)
            height = video_info[format_type].get("height", 0)

            for url in video_info[format_type]["url_list"]:
                all_sources.append({
                    "url": url,
                    "width": width,
                    "height": height,
                    "quality_type": 0,  # 主要格式没有quality_type，使用0作为默认值
                    "quality_score": width * height,
                    "orientation": get_orientation(width, height)
                })

    # 首先按quality_type排序（1是最高质量，其他按数字升序）
    # 然后按分辨率得分排序（宽x高）
    all_sources.sort(key=lambda x: (
        0 if x["quality_type"] == 1 else x["quality_type"],  # quality_type=1优先
        -x["quality_score"]  # 高分辨率优先
    ))

    # 去重并保留排序顺序
    unique_sources = []
    seen_urls = set()

    for source in all_sources:
        if source["url"] not in seen_urls:
            unique_sources.append(source)
            seen_urls.add(source["url"])

    return unique_sources


# 辅助函数：从TikTok视频数据中提取URL和宽高信息
def extract_tiktok_video_urls_with_info(video_data):
    """
    提取TikTok视频URL及其宽高信息，按质量排序但不过滤方向

    参数:
        video_data: 视频数据JSON对象

    返回:
        list: 包含URL和宽高信息的字典列表
    """
    if "video" not in video_data:
        return []

    video_info = video_data["video"]
    all_sources = []

    # 判断视频方向的辅助函数
    def get_orientation(width, height):
        if width > height:
            return "landscape"  # 横屏
        elif height > width:
            return "portrait"  # 竖屏
        else:
            return "square"  # 正方形

    # 处理bit_rate数组中的视频源
    if "bit_rate" in video_info:
        for bit_rate in video_info["bit_rate"]:
            if "play_addr" in bit_rate and "url_list" in bit_rate["play_addr"]:
                width = bit_rate["play_addr"].get("width", 0)
                height = bit_rate["play_addr"].get("height", 0)
                quality_type = bit_rate.get("quality_type", 999)

                for url in bit_rate["play_addr"]["url_list"]:
                    all_sources.append({
                        "url": url,
                        "width": width,
                        "height": height,
                        "quality_type": quality_type,
                        "quality_score": width * height,
                        "orientation": get_orientation(width, height)
                    })

    # 处理主要play_addr视频格式
    if "play_addr" in video_info and "url_list" in video_info["play_addr"]:
        width = video_info["play_addr"].get("width", 0)
        height = video_info["play_addr"].get("height", 0)

        for url in video_info["play_addr"]["url_list"]:
            all_sources.append({
                "url": url,
                "width": width,
                "height": height,
                "quality_type": 0,  # 主要格式没有quality_type，使用0作为默认值
                "quality_score": width * height,
                "orientation": get_orientation(width, height)
            })

    # 按质量排序 (先按quality_type，然后按分辨率)
    all_sources.sort(key=lambda x: (
        x.get("quality_type", 999),  # 低quality_type值优先
        -x.get("quality_score", 0)  # 高分辨率优先
    ))

    # 去重并保留排序顺序
    unique_sources = []
    seen_urls = set()

    for source in all_sources:
        if source["url"] not in seen_urls:
            unique_sources.append(source)
            seen_urls.add(source["url"])

    return unique_sources


# 辅助函数：从Instagram视频数据中提取URL和宽高信息
def extract_instagram_video_urls_with_info(video_data):
    """
    提取Instagram视频URL及其宽高信息，按质量排序但不过滤方向

    参数:
        video_data: 视频数据JSON对象

    返回:
        list: 包含URL和宽高信息的字典列表
    """
    all_sources = []
    media_data = video_data.get("media", {})

    if not media_data:
        return all_sources

    # 判断视频方向的辅助函数
    def get_orientation(width, height):
        if width > height:
            return "landscape"  # 横屏
        elif height > width:
            return "portrait"  # 竖屏
        else:
            return "square"  # 正方形

    # 处理video_versions数组中的视频源
    if "video_versions" in media_data:
        for version in media_data["video_versions"]:
            url = version.get("url", "")
            width = version.get("width", 0)
            height = version.get("height", 0)

            if url:
                all_sources.append({
                    "url": url,
                    "width": width,
                    "height": height,
                    "quality_type": version.get("type", 0),  # 某些版本可能有type字段表示质量类型
                    "quality_score": width * height,
                    "orientation": get_orientation(width, height)
                })

    # 如果有独立的高清视频URL（来自单独的API调用）
    if "video_url" in media_data:
        url = media_data.get("video_url", "")
        width = media_data.get("width", 0)
        height = media_data.get("height", 0)

        if url:
            all_sources.append({
                "url": url,
                "width": width,
                "height": height,
                "quality_type": 1,  # 假设这是最高质量版本
                "quality_score": width * height,
                "orientation": get_orientation(width, height)
            })

    # 按质量分数排序（高质量在前）
    all_sources.sort(key=lambda x: -x["quality_score"])

    # 去重并保留排序顺序
    unique_sources = []
    seen_urls = set()

    for source in all_sources:
        if source["url"] not in seen_urls:
            unique_sources.append(source)
            seen_urls.add(source["url"])

    return unique_sources


# 辅助函数：从快手视频数据中提取URL和宽高信息
def extract_kuaishou_video_urls_with_info(video_data):
    """
    提取快手视频URL及其宽高信息，按质量排序但不过滤方向

    参数:
        video_data: 视频数据JSON对象

    返回:
        list: 包含URL和宽高信息的字典列表
    """
    all_sources = []

    # 判断视频方向的辅助函数
    def get_orientation(width, height):
        if width > height:
            return "landscape"  # 横屏
        elif height > width:
            return "portrait"  # 竖屏
        else:
            return "square"  # 正方形

    # 从streamManifest中提取视频信息
    if "streamManifest" in video_data:
        stream_manifest = video_data.get("streamManifest", {})

        # 快手的视频链接在adaptationSet/representation中
        adaptation_sets = stream_manifest.get("adaptationSet", [])
        for adaptation_set in adaptation_sets:
            representations = adaptation_set.get("representation", [])
            for representation in representations:
                # 获取宽高和质量信息
                width = representation.get("width", 0)
                height = representation.get("height", 0)
                quality = representation.get("quality", 0)

                # 添加主URL
                main_url = representation.get("url")
                if main_url:
                    all_sources.append({
                        "url": main_url,
                        "width": width,
                        "height": height,
                        "quality_type": quality,
                        "quality_score": width * height,
                        "orientation": get_orientation(width, height)
                    })

                # 添加备用URL
                backup_urls = representation.get("backupUrl", [])
                for backup_url in backup_urls:
                    if backup_url:
                        all_sources.append({
                            "url": backup_url,
                            "width": width,
                            "height": height,
                            "quality_type": quality,
                            "quality_score": width * height,
                            "orientation": get_orientation(width, height)
                        })

    # 还可以从main_mv_urls中获取额外的视频链接（通常是高清链接）
    if "main_mv_urls" in video_data:
        main_mv_urls = video_data.get("main_mv_urls", [])

        # 假设这些链接的质量较高，但没有明确的宽高信息
        # 尝试从其他地方获取宽高
        width = 0
        height = 0

        # 如果有adaptationSet中的宽高信息，使用它作为参考
        if all_sources and all_sources[0].get("width") > 0 and all_sources[0].get("height") > 0:
            width = all_sources[0].get("width")
            height = all_sources[0].get("height")

        for mv_url_obj in main_mv_urls:
            url = mv_url_obj.get("url")
            if url:
                all_sources.append({
                    "url": url,
                    "width": width,
                    "height": height,
                    "quality_type": 0,  # 假定这些是高质量链接
                    "quality_score": width * height if width > 0 and height > 0 else 999999,  # 如果没有宽高，给予高分
                    "orientation": get_orientation(width, height) if width > 0 and height > 0 else "unknown"
                })

    # 按质量分数排序（高质量在前）
    all_sources.sort(key=lambda x: (
        -x.get("quality_type", 0),  # 高质量类型在前
        -x.get("quality_score", 0)  # 高分辨率在前
    ))

    # 去重并保留排序顺序
    unique_sources = []
    seen_urls = set()

    for source in all_sources:
        if source["url"] not in seen_urls:
            unique_sources.append(source)
            seen_urls.add(source["url"])

    return unique_sources


# 视频方向筛选函数（通用，可用于抖音和TikTok）
def filter_urls_by_orientation(url_list, orientation_setting="both"):
    """
    根据方向设置筛选URL

    参数:
        url_list: URL列表或包含URL和宽高信息的列表
        orientation_setting: 视频方向设置，可选值: "both"(全部), "portrait"(仅竖屏), "landscape"(仅横屏)

    返回:
        tuple: (筛选后的URL列表, 筛选结果信息)
    """
    filtered_urls = []
    result_info = ""

    # 检查URL列表类型（是普通URL列表还是包含宽高信息的字典列表）
    is_detailed_list = False
    if url_list and isinstance(url_list, list) and len(url_list) > 0:
        if isinstance(url_list[0], dict) and "url" in url_list[0] and "width" in url_list[0] and "height" in url_list[0]:
            is_detailed_list = True
            logger.info("检测到包含宽高信息的URL列表")

    # 根据列表类型和方向设置进行筛选
    if is_detailed_list:
        # 如果是详细列表（包含宽高信息），根据方向设置筛选
        if orientation_setting == "both":
            # 不需要过滤，使用所有URL
            filtered_urls = [url_info["url"] for url_info in url_list]
            result_info = f"方向设置为 'both'，保留所有 {len(filtered_urls)} 个URL"
        else:
            # 根据方向设置过滤URL
            for url_info in url_list:
                width = url_info.get("width", 0)
                height = url_info.get("height", 0)

                # 如果没有宽高信息，保留该URL
                if width == 0 or height == 0:
                    filtered_urls.append(url_info["url"])
                    continue

                is_landscape = width > height
                is_portrait = height > width

                # 根据设置筛选
                if (orientation_setting == "landscape" and is_landscape) or \
                        (orientation_setting == "portrait" and is_portrait):
                    filtered_urls.append(url_info["url"])

            result_info = f"方向设置为 '{orientation_setting}'，过滤后保留 {len(filtered_urls)}/{len(url_list)} 个URL"
    else:
        # 如果是普通URL列表，无法筛选方向，直接使用所有URL
        filtered_urls = url_list
        result_info = f"普通URL列表，无法筛选方向，使用所有 {len(filtered_urls)} 个URL"

    return filtered_urls, result_info


# 处理来自单独API调用返回的单个视频的辅助函数
def extract_instagram_single_video_info(video_response):
    """
    从单个视频API响应中提取URL和宽高信息

    参数:
        video_response: API响应

    返回:
        list: 包含URL和宽高信息的字典列表
    """
    all_sources = []

    if not video_response or video_response.get("code") != 200:
        return all_sources

    post_data = video_response.get("data", {})

    # 判断视频方向的辅助函数
    def get_orientation(width, height):
        if width > height:
            return "landscape"  # 横屏
        elif height > width:
            return "portrait"  # 竖屏
        else:
            return "square"  # 正方形

    # 检查是否为视频且视频URL存在
    if post_data.get("is_video", False) and "video_url" in post_data:
        url = post_data.get("video_url", "")
        width = post_data.get("width", 0)
        height = post_data.get("height", 0)

        if url:
            all_sources.append({
                "url": url,
                "width": width,
                "height": height,
                "quality_type": 1,  # 假设这是最高质量版本
                "quality_score": width * height,
                "orientation": get_orientation(width, height)
            })

    return all_sources


class MonitorService:
    def __init__(self, db=None):
        self.api_service = ApiService()
        self.db = db
        self.api_token = None
        self.client = None

        self.download_dir = os.path.join("app", "static", "downloads")
        os.makedirs(self.download_dir, exist_ok=True)

        # 创建API服务
        self.api_service = ApiService(self.db)

    def set_db(self, db):
        """设置数据库会话"""
        self.db = db

    def get_api_token(self):
        """获取API令牌"""
        if self.db is None:
            logger.warn("警告: 数据库会话未设置")
            return ""

        token = SystemSetting.get_value(self.db, "api_token")
        if not token:
            token = ""

        if token != self.api_token:
            self.api_token = token
            self.client = httpx.AsyncClient(
                headers={"Authorization": f"Bearer {self.api_token}"},
                timeout=180
            )

        return token

    # TikTok 相关方法
    async def add_tiktok_user_with_sequence(self, db: Session, username: str, sequence_number: str,
                                            category: str = None):
        try:
            # 检查用户是否已存在
            existing_user = db.query(MonitoredUser).filter(
                MonitoredUser.platform == "tiktok",
                MonitoredUser.username == username
            ).first()

            if existing_user:
                # 如果提供了新序号，且用户没有序号，则更新序号
                if sequence_number and not existing_user.sequence_number:
                    existing_user.sequence_number = sequence_number

                # 如果提供了新分类，且用户没有分类，则更新分类
                if category and not existing_user.category:
                    existing_user.category = category

                db.commit()
                logger.info(f"TikTok用户已存在: {existing_user.username}，跳过添加")
                return existing_user

            # 获取用户信息
            logger.info(f"开始获取TikTok用户信息: username={username}")
            response = await self.api_service.get_tiktok_user(username)
            if not response:
                logger.error(f"获取TikTok用户信息失败: API返回空响应")
                return None

            if response.get("code") != 200:
                logger.error(f"获取TikTok用户信息失败: {response.get('message', '未知错误')}")
                return None

            user_data = response.get("data", {}).get("user", {})
            if not user_data:
                logger.error(f"未找到TikTok用户数据: {response}")
                return None

            # 只保存相关的用户信息
            relevant_info = {
                "username": username,
                "sec_uid": user_data.get("sec_uid", ""),
                "user_id": user_data.get("uid", ""),
                "signature": user_data.get("signature", ""),
                "visible_videos_count": user_data.get("visible_videos_count", 0),
                "sequence_number": sequence_number
            }

            # 如果有头像信息，也保存
            if "avatar_thumb" in user_data:
                relevant_info["avatar_thumb"] = user_data["avatar_thumb"]

            # 创建新用户
            new_user = MonitoredUser(
                platform="tiktok",
                username=username,
                sec_uid=user_data.get("sec_uid", ""),
                user_id=user_data.get("uid", ""),
                profile_info=json.dumps(relevant_info),
                last_video_count=user_data.get("visible_videos_count", 0),
                category=category,
                sequence_number=sequence_number
            )

            db.add(new_user)
            db.commit()
            db.refresh(new_user)

            logger.info(
                f"已添加TikTok用户: {username}, 视频数: {user_data.get('visible_videos_count', 0)}, 分类: {category}")
            return new_user
        except Exception as e:
            logger.error(f"添加TikTok用户出错: {str(e)}", exc_info=True)
            return None

    async def check_tiktok_updates(self, db: Session, user: MonitoredUser, client_id: str = None):
        logger.info(f"检查TikTok用户更新: {user.username} (ID: {user.id})")

        if client_id:
            await send_progress(client_id, {
                "type": "info",
                "message": f"正在获取TikTok用户 {user.username} 的信息"
            })

        response = await self.api_service.get_tiktok_user(user.username)
        if not response or response.get("code") != 200:
            if client_id:
                await send_progress(client_id, {
                    "type": "warning",
                    "message": f"获取TikTok用户 {user.username} 信息失败"
                })
            logger.error(f"获取用户信息失败: {response}")
            return False

        user_data = response.get("data", {}).get("user", {})
        if not user_data:
            if client_id:
                await send_progress(client_id, {
                    "type": "warning",
                    "message": f"未找到TikTok用户 {user.username} 的数据"
                })
            logger.warning(f"获取用户信息失败: {response}")
            return False

        current_count = user_data.get("visible_videos_count", 0)
        last_count = user.last_video_count

        if client_id:
            await send_progress(client_id, {
                "type": "info",
                "message": f"TikTok用户 {user.username} 当前视频数: {current_count}, 上次记录: {last_count}"
            })

        logger.info(f"用户 {user.username} - 当前视频数: {current_count}, 上次记录: {last_count}")
        if current_count > last_count:
            # 获取新视频
            new_count = current_count - last_count
            if client_id:
                await send_progress(client_id, {
                    "type": "update",
                    "message": f"发现TikTok用户 {user.username} 有 {new_count} 个新视频，开始获取"
                })

            logger.info(f"发现 {new_count} 个新视频，开始获取")
            await self.fetch_tiktok_videos(db, user, new_count, client_id)

            # 只保存相关的用户信息
            try:
                existing_info = json.loads(user.profile_info)
            except:
                existing_info = {}

            relevant_info = {
                "username": user.username,
                "sec_uid": user.sec_uid,
                "signature": user_data.get("signature", existing_info.get("signature", "")),
                "visible_videos_count": current_count
            }

            # 如果有头像信息，也保存
            if "avatar_thumb" in user_data:
                relevant_info["avatar_thumb"] = user_data["avatar_thumb"]
            elif "avatar_thumb" in existing_info:
                relevant_info["avatar_thumb"] = existing_info["avatar_thumb"]

            # 显式打印更新前后的值
            logger.info(f"更新用户 {user.username} - 视频数从 {user.last_video_count} 更新为 {current_count}")
            # 更新用户信息
            user.last_video_count = current_count
            user.profile_info = json.dumps(relevant_info)
            user.last_checked = get_local_time()

            try:
                db.commit()
                if client_id:
                    await send_progress(client_id, {
                        "type": "success",
                        "message": f"已更新TikTok用户 {user.username} 信息，新视频计数: {current_count}"
                    })
                logger.info(f"数据库更新成功 - 用户 {user.username} 新视频计数: {current_count}")
            except Exception as e:
                db.rollback()
                if client_id:
                    await send_progress(client_id, {
                        "type": "error",
                        "message": f"更新TikTok用户 {user.username} 信息失败: {str(e)}"
                    })
                logger.error(f"数据库更新失败: {str(e)}")
                return False

            # 验证更新是否成功
            db.refresh(user)
            logger.info(f"验证更新 - 用户 {user.username} 当前视频计数: {user.last_video_count}")

            return True

            # 只更新最后检查时间
        user.last_checked = get_local_time()
        try:
            db.commit()
            if client_id:
                await send_progress(client_id, {
                    "type": "info",
                    "message": f"TikTok用户 {user.username} 没有新视频，仅更新检查时间"
                })
            logger.info("没有新视频，仅更新检查时间")
        except Exception as e:
            db.rollback()
            if client_id:
                await send_progress(client_id, {
                    "type": "error",
                    "message": f"更新TikTok用户 {user.username} 检查时间失败: {str(e)}"
                })
            logger.error(f"更新检查时间失败: {str(e)}")

        return False

    async def fetch_tiktok_videos(self, db: Session, user: MonitoredUser, count: int, client_id: str = None):
        logger.info(f"开始获取TikTok用户 {user.username} 的 {count} 个新视频")
        if client_id:
            await send_progress(client_id, {
                "type": "info",
                "message": f"正在获取TikTok用户 {user.username} 的视频列表"
            })

        # 获取视频方向设置
        orientation_setting = SystemSetting.get_value(db, "download_video_orientation", "both")
        logger.info(f"视频方向设置: {orientation_setting}")

        # 跟踪已处理的视频数量
        processed_count = 0
        # 跟踪已跳过的置顶视频数量
        skipped_top_count = 0
        # 分页加载参数
        max_cursor = 0
        # 每页请求的视频数量
        page_size = 20  # TikTok API 通常限制每页 20 个
        # 已获取的所有有效视频
        all_valid_videos = []

        # 循环获取视频，直到达到目标数量或者没有更多视频
        while processed_count < count:
            # 使用API获取视频列表，传入分页参数
            response = await self.api_service.get_tiktok_videos(user.sec_uid, max_cursor=max_cursor, count=page_size)

            if not response or response.get("code") != 200:
                logger.warn(f"API返回错误: {response}")
                if client_id:
                    await send_progress(client_id, {
                        "type": "warning",
                        "message": f"获取TikTok用户 {user.username} 的视频列表失败"
                    })
                break  # 出错时退出循环

            videos_data = response.get("data", {}).get("aweme_list", [])
            next_max_cursor = response.get("data", {}).get("max_cursor", 0)
            has_more = response.get("data", {}).get("has_more", 0)

            if not videos_data:
                logger.warn("没有找到更多视频数据")
                if client_id:
                    await send_progress(client_id, {
                        "type": "info",
                        "message": f"未找到更多TikTok用户 {user.username} 的视频数据"
                    })
                break  # 没有更多视频，退出循环

            logger.info(f"获取到第 {max_cursor} 页，找到 {len(videos_data)} 个视频")

            # 过滤掉置顶视频，只保留普通视频
            valid_videos = []
            for video in videos_data:
                aweme_id = video.get("aweme_id", "")
                aweme_type = video.get("aweme_type", 1)
                is_top = video.get("is_top", 0)

                if is_top == 1:
                    skipped_top_count += 1
                    logger.info(f"跳过置顶视频: {aweme_id}")
                    continue

                if aweme_type != 0:
                    logger.info(f"跳过非普通视频 (aweme_type={aweme_type}): {aweme_id}")
                    continue

                # 检查视频是否已存在
                existing_video = db.query(Video).filter(
                    Video.platform == "tiktok",
                    Video.video_id == aweme_id
                ).first()

                if existing_video:
                    logger.info(f"视频已存在，跳过: {aweme_id}")
                    continue

                valid_videos.append(video)

            # 将有效视频添加到总列表
            all_valid_videos.extend(valid_videos)
            processed_count += len(valid_videos)

            if client_id:
                await send_progress(client_id, {
                    "type": "info",
                    "message": f"找到TikTok用户 {user.username} 的 {len(valid_videos)} 个有效视频，总计 {processed_count} 个"
                })

            # 如果已经处理足够的视频或者没有更多页，退出循环
            if processed_count >= count or not has_more == 0 or next_max_cursor == max_cursor:
                break

            # 更新游标，准备获取下一页
            max_cursor = next_max_cursor

            # 添加延迟，避免频繁请求API
            await asyncio.sleep(1)

        logger.info(f"共找到 {len(all_valid_videos)} 个有效视频，跳过 {skipped_top_count} 个置顶视频")

        # 如果没有找到有效视频，则返回
        if not all_valid_videos:
            if client_id:
                await send_progress(client_id, {
                    "type": "warning",
                    "message": f"未找到TikTok用户 {user.username} 的有效视频"
                })
            return

        # 处理找到的有效视频（只处理需要的数量）
        videos_to_process = all_valid_videos[:count]
        for i, video_data in enumerate(videos_to_process):
            aweme_id = video_data.get("aweme_id", "")

            if client_id:
                await send_progress(client_id, {
                    "type": "processing",
                    "message": f"处理TikTok视频 {i + 1}/{len(videos_to_process)}: {aweme_id}"
                })

            # 提取初始视频链接及其宽高信息
            original_url_list_with_info = extract_tiktok_video_urls_with_info(video_data)
            logger.info(f"找到 {len(original_url_list_with_info)} 个原始视频链接")

            # 尝试通过单个视频API获取更高清晰度的链接
            hd_url_list_with_info = []

            try:
                logger.info(f"正在获取高清视频链接: {aweme_id}")
                if client_id:
                    await send_progress(client_id, {
                        "type": "info",
                        "message": f"正在获取TikTok视频 {aweme_id} 的高清链接"
                    })

                hd_video_response = await self.api_service.get_tiktok_single_video(aweme_id)

                if hd_video_response and hd_video_response.get("code") == 200:
                    aweme_details = hd_video_response.get("data", {}).get("aweme_details", [])

                    if aweme_details and len(aweme_details) > 0:
                        aweme_detail = aweme_details[0]

                        # 提取高清视频URL及其宽高信息
                        hd_url_list_with_info = extract_tiktok_video_urls_with_info(aweme_detail)

                        if hd_url_list_with_info:
                            logger.info(f"找到 {len(hd_url_list_with_info)} 个高清视频链接")

                            if client_id:
                                await send_progress(client_id, {
                                    "type": "info",
                                    "message": f"找到TikTok视频 {aweme_id} 的 {len(hd_url_list_with_info)} 个高清链接"
                                })
                        else:
                            logger.info("未找到高清视频链接")

            except Exception as e:
                logger.info(f"获取高清视频链接时出错: {str(e)}")
                if client_id:
                    await send_progress(client_id, {
                        "type": "warning",
                        "message": f"获取TikTok视频 {aweme_id} 高清链接时出错: {str(e)}"
                    })

            # 合并URL列表，高清链接优先，且避免重复
            all_urls_with_info = []
            seen_urls = set()

            # 先添加高清链接
            for url_info in hd_url_list_with_info:
                if url_info["url"] not in seen_urls:
                    all_urls_with_info.append(url_info)
                    seen_urls.add(url_info["url"])

            # 再添加原始链接（不重复的）
            for url_info in original_url_list_with_info:
                if url_info["url"] not in seen_urls:
                    all_urls_with_info.append(url_info)
                    seen_urls.add(url_info["url"])

            # 如果没有URL可用，记录错误并继续下一个
            if not all_urls_with_info:
                logger.warn(f"未找到任何可用的下载链接，跳过视频: {aweme_id}")
                if client_id:
                    await send_progress(client_id, {
                        "type": "warning",
                        "message": f"没有找到TikTok视频 {aweme_id} 的可用下载链接，跳过"
                    })
                continue

            logger.info(f"共获取到 {len(all_urls_with_info)} 个下载URL")

            # 在这里应用视频方向筛选
            filtered_urls, filter_info = filter_urls_by_orientation(all_urls_with_info, orientation_setting)
            logger.info(f"视频方向筛选结果: {filter_info}")

            # 如果筛选后没有可用的URL，跳过该视频
            if not filtered_urls:
                logger.info(f"视频 {aweme_id} 没有符合方向设置({orientation_setting})的链接，跳过")
                if client_id:
                    await send_progress(client_id, {
                        "type": "warning",
                        "message": f"视频 {aweme_id} 没有符合方向设置({orientation_setting})的链接，跳过"
                    })
                continue

            # 保存视频信息
            new_video = Video(
                user_id=user.id,
                platform="tiktok",
                video_id=video_data.get("aweme_id", ""),
                title=video_data.get("desc", ""),
                download_url=json.dumps(filtered_urls)  # 只保存筛选后的URL列表
            )

            db.add(new_video)
            db.commit()
            db.refresh(new_video)
            logger.info(f"视频信息已保存到数据库: ID={new_video.id}")

            if client_id:
                await send_progress(client_id, {
                    "type": "info",
                    "message": f"TikTok视频 {aweme_id} 信息已保存到数据库，开始下载，共 {len(filtered_urls)} 个链接"
                })

            # 下载视频（使用筛选后的URL列表）
            logger.info(f"开始下载视频 {aweme_id}, 有 {len(filtered_urls)} 个可用链接")
            success = await self.download_video(db, new_video, filtered_urls, user.username, user.sequence_number,
                                                user.category, client_id)
            if success:
                await send_progress(client_id, {
                    "type": "success",
                    "message": f"TikTok视频 {aweme_id} 下载成功"
                })
            else:
                await send_progress(client_id, {
                    "type": "error",
                    "message": f"TikTok视频 {aweme_id} 下载失败"
                })
            logger.info(f"视频下载结果: {'成功' if success else '失败'}")

    # 抖音相关方法
    async def add_douyin_user_with_sequence(self, db: Session, sec_uid: str, sequence_number: str,
                                            category: str = None):
        try:
            # 检查用户是否已存在
            existing_user = db.query(MonitoredUser).filter(
                MonitoredUser.platform == "douyin",
                MonitoredUser.sec_uid == sec_uid
            ).first()

            if existing_user:
                # 如果需要，使用序列号和类别更新现有用户
                if sequence_number and not existing_user.sequence_number:
                    existing_user.sequence_number = sequence_number

                if category and not existing_user.category:
                    existing_user.category = category

                db.commit()
                logger.info(f"抖音用户已存在: {existing_user.username}，跳过添加")
                return existing_user

            # 获取用户信息
            logger.info(f"开始获取抖音用户信息: sec_uid={sec_uid}")
            response = await self.api_service.get_douyin_user(sec_uid)
            if not response:
                logger.error(f"获取抖音用户信息失败: API返回空响应")
                return None

            if response.get("code") != 200:
                logger.error(f"获取抖音用户信息失败: {response.get('message', '未知错误')}")
                return None

            user_data = response.get("data", {}).get("user", {})
            if not user_data:
                logger.error(f"未找到抖音用户数据: {response}")
                return None

            username = user_data.get("nickname", "")
            relevant_info = {
                "username": username,
                "sec_uid": sec_uid,
                "signature": user_data.get("signature", ""),
                "aweme_count": user_data.get("aweme_count", 0),
                "sequence_number": sequence_number
            }

            # 如果有头像信息，也保存
            if "cover_and_head_image_info" in user_data:
                relevant_info["cover_and_head_image_info"] = {
                    "profile_cover_list": user_data["cover_and_head_image_info"].get("profile_cover_list", [])
                }

            # 创建新用户
            new_user = MonitoredUser(
                platform="douyin",
                username=username,
                sec_uid=sec_uid,
                user_id=user_data.get("uid", ""),
                profile_info=json.dumps(relevant_info),
                last_video_count=user_data.get("aweme_count", 0),
                category=category,  # 添加分类
                sequence_number=sequence_number
            )

            db.add(new_user)
            db.commit()
            db.refresh(new_user)

            logger.info(f"已添加抖音用户: {username}, 视频数: {user_data.get('aweme_count', 0)}, 分类: {category}")
            return new_user
        except Exception as e:
            logger.error(f"添加抖音用户出错: {str(e)}", exc_info=True)
            return None

    async def check_douyin_updates(self, db: Session, user: MonitoredUser, client_id: str = None):
        logger.info(f"检查抖音用户更新: {user.username} (ID: {user.id})")

        if client_id:
            await send_progress(client_id, {
                "type": "info",
                "message": f"正在获取抖音用户 {user.username} 的信息"
            })

        response = await self.api_service.get_douyin_user(user.sec_uid)
        if not response or response.get("code") != 200:
            if client_id:
                await send_progress(client_id, {
                    "type": "warning",
                    "message": f"获取抖音用户 {user.username} 信息失败"
                })
            logger.error(f"获取用户信息失败: {response}")
            return False

        user_data = response.get("data", {}).get("user", {})
        if not user_data:
            if client_id:
                await send_progress(client_id, {
                    "type": "warning",
                    "message": f"未找到抖音用户 {user.username} 的数据"
                })
            logger.error(f"未找到用户数据: {response}")
            return False

        current_count = int(user_data.get("aweme_count", 0))  # 确保转换为整数
        last_count = int(user.last_video_count) if user.last_video_count else 0  # 确保转换为整数

        logger.info(f"用户 {user.username} - 当前视频数: {current_count}, 上次记录: {last_count} (ID: {user.id})")

        if client_id:
            await send_progress(client_id, {
                "type": "info",
                "message": f"抖音用户 {user.username} 当前视频数: {current_count}, 上次记录: {last_count}"
            })

        if current_count > last_count:
            # 获取新视频
            new_count = current_count - last_count
            if client_id:
                await send_progress(client_id, {
                    "type": "update",
                    "message": f"发现抖音用户 {user.username} 有 {new_count} 个新视频，开始获取"
                })

            logger.info(f"发现 {new_count} 个新视频，开始获取")
            await self.fetch_douyin_videos(db, user, new_count, client_id)

            # 只保存相关的用户信息
            try:
                existing_info = json.loads(user.profile_info) if user.profile_info else {}
            except:
                existing_info = {}

            relevant_info = {
                "username": user.username,
                "sec_uid": user.sec_uid,
                "signature": user_data.get("signature", existing_info.get("signature", "")),
                "aweme_count": current_count
            }

            # 如果有头像信息，也保存
            if "cover_and_head_image_info" in user_data:
                relevant_info["cover_and_head_image_info"] = {
                    "profile_cover_list": user_data["cover_and_head_image_info"].get("profile_cover_list", [])
                }

            # 显式打印更新前后的值
            logger.info(f"更新用户 {user.username} - 视频数从 {user.last_video_count} 更新为 {current_count}")

            # 更新用户信息
            user.last_video_count = current_count
            user.profile_info = json.dumps(relevant_info)
            user.last_checked = get_local_time()

            try:
                db.commit()
                if client_id:
                    await send_progress(client_id, {
                        "type": "success",
                        "message": f"已更新抖音用户 {user.username} 信息，新视频计数: {current_count}"
                    })
                logger.info(f"数据库更新成功 - 用户 {user.username} 新视频计数: {current_count}")
            except Exception as e:
                db.rollback()
                if client_id:
                    await send_progress(client_id, {
                        "type": "error",
                        "message": f"更新抖音用户 {user.username} 信息失败: {str(e)}"
                    })
                logger.info(f"数据库更新失败: {str(e)}")
                return False

            # 验证更新是否成功
            db.refresh(user)
            logger.info(f"验证更新 - 用户 {user.username} 当前视频计数: {user.last_video_count}")

            return True

        # 只更新最后检查时间
        user.last_checked = get_local_time()
        try:
            db.commit()
            if client_id:
                await send_progress(client_id, {
                    "type": "info",
                    "message": f"抖音用户 {user.username} 没有新视频，仅更新检查时间"
                })
            logger.info("没有新视频，仅更新检查时间")
        except Exception as e:
            db.rollback()
            if client_id:
                await send_progress(client_id, {
                    "type": "error",
                    "message": f"更新抖音用户 {user.username} 检查时间失败: {str(e)}"
                })
            logger.error(f"更新检查时间失败: {str(e)}")

        return False

    async def fetch_douyin_videos(self, db: Session, user: MonitoredUser, count: int, client_id: str = None):
        if client_id:
            await send_progress(client_id, {
                "type": "info",
                "message": f"正在获取抖音用户 {user.username} 的视频列表"
            })

        # 获取视频方向设置（仅用于记录日志）
        orientation_setting = SystemSetting.get_value(db, "download_video_orientation", "both")
        logger.info(f"视频方向设置: {orientation_setting}")

        # 跟踪已处理的视频数量
        processed_count = 0
        # 跟踪已跳过的置顶视频数量
        skipped_top_count = 0
        # 分页加载参数
        max_cursor = 0
        # 每页请求的视频数量
        page_size = 20  # 抖音 API 通常限制每页 20 个
        # 已获取的所有有效视频
        all_valid_videos = []

        # 循环获取视频，直到达到目标数量或者没有更多视频
        while processed_count < count:
            # 使用API获取视频列表，传入分页参数
            response = await self.api_service.get_douyin_videos(user.sec_uid, max_cursor=max_cursor, count=page_size)

            if not response or response.get("code") != 200:
                logger.error(f"API返回错误: {response}")
                if client_id:
                    await send_progress(client_id, {
                        "type": "warning",
                        "message": f"获取抖音用户 {user.username} 的视频列表失败"
                    })
                break  # 出错时退出循环

            videos_data = response.get("data", {}).get("aweme_list", [])

            next_max_cursor = response.get("data", {}).get("max_cursor", 0)
            has_more = response.get("data", {}).get("has_more", 0)

            if not videos_data:
                logger.info("没有找到更多视频数据")
                if client_id:
                    await send_progress(client_id, {
                        "type": "info",
                        "message": f"未找到更多抖音用户 {user.username} 的视频数据"
                    })
                break  # 没有更多视频，退出循环

            logger.info(f"获取到第 {max_cursor} 页，找到 {len(videos_data)} 个视频")

            # 过滤掉置顶视频，只保留普通视频
            valid_videos = []
            for video in videos_data:
                aweme_id = video.get("aweme_id", "")
                aweme_type = video.get("aweme_type", 1)
                is_top = video.get("is_top", 0)

                if is_top == 1:
                    skipped_top_count += 1
                    logger.warn(f"跳过置顶视频: {aweme_id}")
                    continue

                if aweme_type != 0:
                    logger.warn(f"跳过非普通视频 (aweme_type={aweme_type}): {aweme_id}")
                    continue

                # 检查视频是否已存在
                existing_video = db.query(Video).filter(
                    Video.platform == "douyin",
                    Video.video_id == aweme_id
                ).first()

                if existing_video:
                    logger.warn(f"视频已存在，跳过: {aweme_id}")
                    continue

                valid_videos.append(video)

            # 将有效视频添加到总列表
            all_valid_videos.extend(valid_videos)
            processed_count += len(valid_videos)

            if client_id:
                await send_progress(client_id, {
                    "type": "info",
                    "message": f"找到抖音用户 {user.username} 的 {len(valid_videos)} 个有效视频，总计 {processed_count} 个"
                })

            # 如果已经处理足够的视频或者没有更多页，退出循环
            if processed_count >= count or not has_more == 0 or next_max_cursor == max_cursor:
                break

            # 更新游标，准备获取下一页
            max_cursor = next_max_cursor

            # 添加延迟，避免频繁请求API
            await asyncio.sleep(1)

        logger.info(f"共找到 {len(all_valid_videos)} 个有效视频，跳过 {skipped_top_count} 个置顶视频")

        # 如果没有找到有效视频，则返回
        if not all_valid_videos:
            if client_id:
                await send_progress(client_id, {
                    "type": "warning",
                    "message": f"未找到抖音用户 {user.username} 的有效视频"
                })
            logger.info(f"未找到抖音用户 {user.username} 的有效视频")
            return

        # 处理找到的有效视频（只处理需要的数量）
        videos_to_process = all_valid_videos[:count]
        for i, video_data in enumerate(videos_to_process):
            aweme_id = video_data.get("aweme_id", "")

            if client_id:
                await send_progress(client_id, {
                    "type": "processing",
                    "message": f"处理抖音视频 {i + 1}/{len(videos_to_process)}: {aweme_id}"
                })

            # 提取初始视频链接（无需考虑方向）
            original_url_list_with_info = extract_douyin_video_urls_with_info(video_data)
            logger.info(f"找到 {len(original_url_list_with_info)} 个原始视频链接")

            # 尝试通过单个视频API获取更高清晰度的链接
            hd_url_list_with_info = []

            try:
                logger.info(f"正在获取高清视频链接: {aweme_id}")
                if client_id:
                    await send_progress(client_id, {
                        "type": "info",
                        "message": f"正在获取抖音视频 {aweme_id} 的高清链接"
                    })

                hd_video_response = await self.api_service.get_douyin_single_video(aweme_id)

                if hd_video_response and hd_video_response.get("code") == 200:
                    aweme_detail = hd_video_response.get("data", {}).get("aweme_detail", {})

                    if aweme_detail:
                        # 提取高清视频URL（无需考虑方向）
                        hd_url_list_with_info = extract_douyin_video_urls_with_info(aweme_detail)

                        if hd_url_list_with_info:
                            logger.info(f"找到 {len(hd_url_list_with_info)} 个高清视频链接")

                            if client_id:
                                await send_progress(client_id, {
                                    "type": "info",
                                    "message": f"找到抖音视频 {aweme_id} 的 {len(hd_url_list_with_info)} 个高清链接"
                                })
                        else:
                            logger.info("未找到高清视频链接")

            except Exception as e:
                if client_id:
                    await send_progress(client_id, {
                        "type": "warning",
                        "message": f"获取抖音视频 {aweme_id} 高清链接时出错: {str(e)}"
                    })
                logger.error(f"获取高清视频链接时出错: {str(e)}")

            # 合并URL列表，高清链接优先，且避免重复
            all_urls_with_info = []
            seen_urls = set()

            # 先添加高清链接
            for url_info in hd_url_list_with_info:
                if url_info["url"] not in seen_urls:
                    all_urls_with_info.append(url_info)
                    seen_urls.add(url_info["url"])

            # 再添加原始链接（不重复的）
            for url_info in original_url_list_with_info:
                if url_info["url"] not in seen_urls:
                    all_urls_with_info.append(url_info)
                    seen_urls.add(url_info["url"])

            # 如果没有URL可用，记录错误并继续下一个
            if not all_urls_with_info:
                logger.warn(f"未找到任何可用的下载链接，跳过视频: {aweme_id}")
                if client_id:
                    await send_progress(client_id, {
                        "type": "warning",
                        "message": f"没有找到抖音视频 {aweme_id} 的可用下载链接，跳过"
                    })
                continue

            logger.info(f"共获取到 {len(all_urls_with_info)} 个下载URL")

            # 在这里应用视频方向筛选
            filtered_urls, filter_info = filter_urls_by_orientation(all_urls_with_info, orientation_setting)
            logger.info(f"视频方向筛选结果: {filter_info}")

            # 如果筛选后没有可用的URL，跳过该视频
            if not filtered_urls:
                logger.info(f"视频 {aweme_id} 没有符合方向设置({orientation_setting})的链接，跳过")
                if client_id:
                    await send_progress(client_id, {
                        "type": "warning",
                        "message": f"视频 {aweme_id} 没有符合方向设置({orientation_setting})的链接，跳过"
                    })
                continue

            import math

            duration_data = video_data.get("duration", 0)

            # # 毫秒 → 秒（向下取整）
            total_seconds = math.floor(duration_data / 1000)
            #
            # # 秒 → 时分秒格式
            # hours = total_seconds // 3600
            # minutes = (total_seconds % 3600) // 60
            # seconds = total_seconds % 60
            #
            # # 格式化为 00:00:00 字符串
            # formatted_duration = f"{hours:02}:{minutes:02}:{seconds:02}"

            new_video = Video(
                user_id=user.id,
                platform="douyin",
                video_id=video_data.get("aweme_id", ""),
                title=video_data.get("desc", ""),
                duration=total_seconds,
                download_url=json.dumps(filtered_urls)  # 只保存筛选后的URL列表
            )

            db.add(new_video)
            db.commit()
            db.refresh(new_video)

            if client_id:
                await send_progress(client_id, {
                    "type": "info",
                    "message": f"抖音视频 {aweme_id} 信息已保存到数据库，开始下载，共 {len(filtered_urls)} 个链接"
                })

            # 下载视频（在下载函数中应用方向筛选）
            logger.info(f"开始下载视频 {aweme_id}, 有 {len(filtered_urls)} 个可用链接")
            success = await self.download_video(db, new_video, filtered_urls, user.username, user.sequence_number,
                                                user.category, client_id)

            # 更新视频状态
            new_video.status = "completed" if success else "failed"
            db.commit()

            if success:
                await send_progress(client_id, {
                    "type": "success",
                    "message": f"抖音视频 {aweme_id} 下载成功"
                })
            else:
                await send_progress(client_id, {
                    "type": "error",
                    "message": f"抖音视频 {aweme_id} 下载失败"
                })
            logger.info(f"视频下载结果: {'成功' if success else '失败'}")

    async def fetch_douyin_hot_videos(self, db: Session, page, page_size, date_window, tags=None,
                                      client_id: str = None):
        """获取抖音热门视频列表并保存到数据库"""
        logger.info(f"开始获取抖音热门视频 (页码: {page}, 每页: {page_size}, 时间窗口: {date_window}小时)")

        if client_id:
            await send_progress(client_id, {
                "type": "info",
                "message": f"正在获取抖音热门视频列表 (页码: {page}, 每页: {page_size})"
            })

        # 调用API获取热门视频
        response = await self.api_service.get_douyin_hot_videos(page, page_size, date_window, tags)

        if not response or response.get("code") != 200:
            logger.error(f"获取抖音热门视频失败: {response}")
            if client_id:
                await send_progress(client_id, {
                    "type": "error",
                    "message": f"获取抖音热门视频失败: {response.get('message', '未知错误')}"
                })
            return None

        # 解析返回的数据
        data = response.get("data", {}).get("data", {})
        page_info = data.get("page", {})
        videos = data.get("objs", [])

        total_count = page_info.get("total", 0)
        current_page = page_info.get("page", 1)

        logger.info(f"获取到 {len(videos)} 个抖音热门视频，总计 {total_count} 个，当前页 {current_page}")

        if client_id:
            await send_progress(client_id, {
                "type": "info",
                "message": f"获取到 {len(videos)} 个抖音热门视频，总计 {total_count} 个"
            })

        # 保存视频信息到数据库
        saved_count = 0
        for index, video in enumerate(videos):
            video_id = video.get("item_id", "")
            if not video_id:
                logger.warn(f"视频数据缺少ID，跳过: {video}")
                continue
            if client_id:
                await send_progress(client_id, {
                    "type": "processing",
                    "current": index + 1,
                    "total": len(videos),
                    "message": f"正在下载第 {index + 1}/{len(videos)} 个视频 (ID: {video_id})"
                })

            # 检查视频是否已存在
            existing_video = db.query(HotVideo).filter(
                HotVideo.platform == "douyin",
                HotVideo.video_id == video_id
            ).first()

            if existing_video:
                logger.info(f"热门视频已存在，更新信息: {video_id}")
                # 可以选择更新已存在视频的排名和其他信息
                existing_video.rank = (page - 1) * page_size + index + 1
                existing_video.play_count = video.get("play_cnt", existing_video.play_count)
                existing_video.like_count = video.get("like_cnt", existing_video.like_count)
                db.commit()
                saved_count += 1
                continue

            # 创建新的热门视频记录
            new_video = HotVideo(
                platform="douyin",
                video_id=video_id,
                title=video.get("item_title", ""),
                cover_url=video.get("item_cover_url", ""),
                duration=video.get("item_duration", 0),
                author=video.get("nick_name", ""),
                avatar_url=video.get("avatar_url", ""),
                fans_count=video.get("fans_cnt", 0),
                play_count=video.get("play_cnt", 0),
                like_count=video.get("like_cnt", 0),
                publish_time=datetime.datetime.fromtimestamp(video.get("publish_time", 0)),
                video_url=video.get("item_url", ""),
                rank=(page - 1) * page_size + index + 1,
                download_status="pending"
            )

            db.add(new_video)

            try:
                db.commit()
                db.refresh(new_video)
                saved_count += 1

                # 尝试获取详细的视频信息和下载链接，但不下载
                if client_id:
                    await send_progress(client_id, {
                        "type": "processing",
                        "message": f"正在获取视频 {video_id} 的详细信息 ({index + 1}/{len(videos)})"
                    })

                # 获取下载链接但不下载
                await self.update_hot_video_details(db, new_video, client_id)

            except Exception as e:
                db.rollback()
                logger.error(f"保存热门视频失败: {str(e)}")
                if client_id:
                    await send_progress(client_id, {
                        "type": "warning",
                        "message": f"保存视频 {video_id} 失败: {str(e)}"
                    })

        if client_id:
            await send_progress(client_id, {
                "type": "success",
                "message": f"成功保存 {saved_count} 个抖音热门视频"
            })

        logger.info(f"成功保存 {saved_count} 个抖音热门视频")

        # 返回分页信息
        return {
            "total": total_count,
            "page": current_page,
            "page_size": page_size,
            "saved_count": saved_count
        }

    async def batch_download_hot_videos(self, db: Session, video_ids: List[int], client_id: str = None):
        """批量下载热门视频"""
        if client_id:
            await send_progress(client_id, {
                "type": "start",
                "message": f"开始批量下载 {len(video_ids)} 个视频",
                "total": len(video_ids)
            })

        success_count = 0
        fail_count = 0

        for i, video_id in enumerate(video_ids):
            try:
                if client_id:
                    await send_progress(client_id, {
                        "type": "processing",
                        "current": i + 1,
                        "total": len(video_ids),
                        "message": f"正在下载第 {i + 1}/{len(video_ids)} 个视频 (ID: {video_id})"
                    })

                # 下载单个视频
                success = await self.download_hot_video(db, video_id, client_id)

                if success:
                    success_count += 1
                else:
                    fail_count += 1

            except Exception as e:
                logger.error(f"下载视频 {video_id} 时出错: {str(e)}")
                fail_count += 1

                if client_id:
                    await send_progress(client_id, {
                        "type": "error",
                        "message": f"下载视频 ID: {video_id} 时出错: {str(e)}"
                    })

        # 发送完成消息
        if client_id:
            await send_progress(client_id, {
                "type": "complete",
                "message": f"批量下载完成: 成功 {success_count} 个，失败 {fail_count} 个"
            })

        logger.info(f"批量下载完成: 成功 {success_count} 个，失败 {fail_count} 个")

        return {
            "success_count": success_count,
            "fail_count": fail_count
        }

    async def update_hot_video_details(self, db: Session, hot_video: HotVideo, client_id: str = None):
        """更新热门视频的详细信息和下载链接"""
        try:
            # 获取视频详情
            video_details = await self.api_service.get_douyin_single_video(hot_video.video_id)

            if not video_details or video_details.get("code") != 200:
                logger.error(f"获取视频详情失败: {video_details}")
                return False

            # 解析下载链接
            aweme_detail = video_details.get("data", {}).get("aweme_detail", {})

            if aweme_detail:
                # 提取高清下载链接
                download_urls = []

                if "video" in aweme_detail and "bit_rate" in aweme_detail["video"]:
                    # 按质量排序 (quality_type=1 通常是最高质量)
                    bit_rates = sorted(
                        aweme_detail["video"]["bit_rate"],
                        key=lambda x: 0 if x.get("quality_type") == 1 else x.get("quality_type", 999)
                    )

                    # 获取所有质量的链接
                    for bit_rate in bit_rates:
                        if "play_addr" in bit_rate and "url_list" in bit_rate["play_addr"]:
                            urls = bit_rate["play_addr"]["url_list"]
                            download_urls.extend([url for url in urls if url not in download_urls])

                # 如果没有从bit_rate中找到，尝试使用普通play_addr
                if not download_urls and "video" in aweme_detail and "play_addr" in aweme_detail["video"]:
                    urls = aweme_detail["video"]["play_addr"].get("url_list", [])
                    download_urls.extend(urls)

                if not download_urls:
                    logger.error(f"无法获取视频 {hot_video.video_id} 的下载链接")
                    return False

                # 更新视频详情
                hot_video.download_url = json.dumps(download_urls)

                # 更新其他可能的字段
                if "desc" in aweme_detail and hot_video.title == "":
                    hot_video.title = aweme_detail.get("desc", "")

                db.commit()
                logger.info(f"已更新视频 {hot_video.video_id} 的详细信息和下载链接")
                return True

        except Exception as e:
            logger.error(f"更新视频详情和下载链接时出错: {str(e)}")
            return False

    async def download_hot_video(self, db: Session, video_id: int, client_id: str = None):
        """下载指定的热门视频"""
        video = db.query(HotVideo).filter(HotVideo.id == video_id).first()
        if not video:
            logger.error(f"未找到视频ID: {video_id}")
            if client_id:
                await send_progress(client_id, {
                    "type": "error",
                    "message": f"未找到视频ID: {video_id}"
                })
            return False

        # 检查是否有下载URL
        if not video.download_url:
            logger.info(f"视频 {video_id} 没有下载链接，尝试获取...")
            if client_id:
                await send_progress(client_id, {
                    "type": "info",
                    "message": f"视频 {video.video_id} 没有下载链接，正在获取..."
                })

            success = await self.update_hot_video_details(db, video, client_id)
            if not success:
                logger.error(f"无法获取视频 {video.video_id} 的下载链接")
                if client_id:
                    await send_progress(client_id, {
                        "type": "error",
                        "message": f"无法获取视频 {video.video_id} 的下载链接"
                    })
                return False

            # 重新从数据库获取视频信息
            db.refresh(video)

        try:
            download_urls = json.loads(video.download_url)
        except:
            logger.error(f"解析下载链接失败: {video.download_url}")
            if client_id:
                await send_progress(client_id, {
                    "type": "error",
                    "message": f"解析下载链接失败: {video.download_url}"
                })
            return False

        if not download_urls:
            logger.error(f"视频 {video.video_id} 没有有效的下载链接")
            return False

        # 设置下载状态为downloading
        video.download_status = "downloading"
        db.commit()

        # 获取当前日期作为文件夹名
        today_date = datetime.datetime.now().strftime("%Y-%m-%d")

        # 创建下载路径
        dir_path = os.path.join(self.download_dir, "hot_videos", today_date)
        os.makedirs(dir_path, exist_ok=True)

        # 从描述中提取简短前缀（最多30个字符）
        title_prefix = ""
        if video.title:
            title_prefix = video.title
            # 添加三个下划线作为连接符
            if title_prefix:
                title_prefix = f"{title_prefix}___"

        # 使用视频ID作为主文件名，前面加上描述前缀
        file_name = f"{title_prefix}{video.video_id}.mp4"
        file_path = os.path.join(dir_path, file_name)

        # 如果文件已存在，添加序号避免覆盖
        counter = 1
        while os.path.exists(file_path):
            file_name = f"{title_prefix}{video.video_id}_{counter}.mp4"
            file_path = os.path.join(dir_path, file_name)
            counter += 1

        logger.info(f"尝试下载视频到: {file_path}")
        if client_id:
            await send_progress(client_id, {
                "type": "downloading",
                "message": f"正在下载视频: {video.title}",
                "video_id": video.id
            })

        # 调用通用下载方法
        success = await download_video_with_urls(
            db,
            download_urls,
            file_path,
            client_id=client_id
        )

        if success:
            # 更新视频状态
            video.download_status = "downloaded"
            relative_path = os.path.relpath(file_path, os.path.join("app", "static"))
            video.local_path = f"/static/{relative_path}"
            video.is_selected = False
            db.commit()

            logger.info(f"视频 {video.video_id} 下载成功: {file_path}")
            if client_id:
                await send_progress(client_id, {
                    "type": "success",
                    "message": f"视频 {video.title} 下载成功"
                })
            return True
        else:
            # 更新视频状态
            video.download_status = "failed"
            db.commit()

            logger.error(f"视频 {video.video_id} 下载失败")
            if client_id:
                await send_progress(client_id, {
                    "type": "error",
                    "message": f"视频 {video.title} 下载失败"
                })
            return False

    # Instagram相关方法
    async def add_instagram_user_with_sequence(self, db: Session, username: str, sequence_number: str,
                                               category: str = None):
        try:
            # 检查用户是否已存在
            existing_user = db.query(MonitoredUser).filter(
                MonitoredUser.platform == "instagram",
                MonitoredUser.username == username
            ).first()

            if existing_user:
                # 如果需要，使用序列号和类别更新现有用户
                if sequence_number and not existing_user.sequence_number:
                    existing_user.sequence_number = sequence_number

                # 如果提供了新分类，且用户没有分类，则更新分类
                if category and not existing_user.category:
                    existing_user.category = category

                db.commit()
                logger.info(f"Instagram用户已存在: {existing_user.username}，跳过添加")
                return existing_user

            # 获取用户信息
            logger.info(f"开始获取Instagram用户信息: username={username}")
            response = await self.api_service.get_instagram_user(username)
            if not response:
                logger.error("获取Instagram用户信息失败: API返回空响应")
                return None

            if response.get("code") != 200:
                logger.error(f"获取Instagram用户信息失败: {response.get('message', '未知错误')}")
                return None

            user_data = response.get("data", {})
            if not user_data:
                logger.error(f"未找到Instagram用户数据: {response}")
                return None

                # 只保存相关的用户信息
            relevant_info = {
                "username": username,
                "pk": user_data.get("pk", ""),
                "profile_pic_url": user_data.get("profile_pic_url", ""),
                "biography": user_data.get("biography", ""),
                "media_count": user_data.get("media_count", 0),
                "sequence_number": sequence_number
            }

            # 创建新用户
            new_user = MonitoredUser(
                platform="instagram",
                username=username,
                user_id=user_data.get("pk", ""),
                profile_info=json.dumps(relevant_info),
                last_video_count=user_data.get("media_count", 0),
                category=category,  # 添加分类
                sequence_number=sequence_number
            )

            db.add(new_user)
            db.commit()
            db.refresh(new_user)

            logger.info(f"已添加Instagram用户: {username}, 视频数: {user_data.get('media_count', 0)}")
            return new_user
        except Exception as e:
            logger.error(f"添加Instagram用户出错: {str(e)}", exc_info=True)
            return None

    async def check_instagram_updates(self, db: Session, user: MonitoredUser, client_id: str = None):
        logger.info(f"检查Instagram用户更新: {user.username} (ID: {user.id})")

        if client_id:
            await send_progress(client_id, {
                "type": "info",
                "message": f"正在获取Instagram用户 {user.username} 的信息"
            })

        response = await self.api_service.get_instagram_user(user.username)
        if not response:
            logger.error(f"获取用户信息失败: {response}")
            if client_id:
                await send_progress(client_id, {
                    "type": "warning",
                    "message": f"获取Instagram用户 {user.username} 信息失败"
                })
            return False

        if response.get("code") != 200:
            logger.error(f"获取Instagram用户信息失败: {response.get('message', '未知错误')}")
            if client_id:
                await send_progress(client_id, {
                    "type": "warning",
                    "message": f"获取Instagram用户 {user.username} 信息失败"
                })
            return None

        user_data = response.get("data", {})
        if not user_data:
            logger.warn(f"未找到用户数据: {response}")
            if client_id:
                await send_progress(client_id, {
                    "type": "warning",
                    "message": f"未找到Instagram用户 {user.username} 的数据"
                })
            return False

        current_count = int(user_data.get("media_count", 0))  # 确保转换为整数
        last_count = int(user.last_video_count) if user.last_video_count else 0  # 确保转换为整数

        logger.info(f"用户 {user.username} - 当前视频数: {current_count}, 上次记录: {last_count} (ID: {user.id})")

        if client_id:
            await send_progress(client_id, {
                "type": "info",
                "message": f"Instagram用户 {user.username} 当前视频数: {current_count}, 上次记录: {last_count}"
            })

        if current_count > last_count:
            # 获取新视频
            new_count = current_count - last_count
            if client_id:
                await send_progress(client_id, {
                    "type": "update",
                    "message": f"发现Instagram用户 {user.username} 有 {new_count} 个新视频，开始获取"
                })
            logger.info(f"发现 {new_count} 个新视频，开始获取")
            await self.fetch_instagram_videos(db, user, new_count, client_id)

            # 只保存相关的用户信息
            try:
                existing_info = json.loads(user.profile_info) if user.profile_info else {}
            except:
                existing_info = {}

            relevant_info = {
                "username": user.username,
                "pk": user_data.get("pk", existing_info.get("pk", "")),
                "profile_pic_url": user_data.get("profile_pic_url", existing_info.get("profile_pic_url", "")),
                "biography": user_data.get("biography", existing_info.get("biography", "")),
                "media_count": current_count
            }

            # 显式打印更新前后的值
            logger.info(f"更新用户 {user.username} - 视频数从 {user.last_video_count} 更新为 {current_count}")

            # 更新用户信息
            user.last_video_count = current_count
            user.profile_info = json.dumps(relevant_info)
            user.last_checked = get_local_time()

            try:
                db.commit()
                if client_id:
                    await send_progress(client_id, {
                        "type": "success",
                        "message": f"已更新Instagram用户 {user.username} 信息，新视频计数: {current_count}"
                    })
                logger.info(f"数据库更新成功 - 用户 {user.username} 新视频计数: {current_count}")
            except Exception as e:
                db.rollback()
                if client_id:
                    await send_progress(client_id, {
                        "type": "error",
                        "message": f"更新Instagram用户 {user.username} 信息失败: {str(e)}"
                    })
                logger.error(f"数据库更新失败: {str(e)}")
                return False

            # 验证更新是否成功
            db.refresh(user)
            logger.info(f"验证更新 - 用户 {user.username} 当前视频计数: {user.last_video_count}")

            return True

        # 只更新最后检查时间
        user.last_checked = get_local_time()
        try:
            db.commit()
            if client_id:
                await send_progress(client_id, {
                    "type": "info",
                    "message": f"Instagram用户 {user.username} 没有新视频，仅更新检查时间"
                })
            logger.warn("没有新视频，仅更新检查时间")
        except Exception as e:
            db.rollback()
            if client_id:
                await send_progress(client_id, {
                    "type": "error",
                    "message": f"更新Instagram用户 {user.username} 检查时间失败: {str(e)}"
                })
            logger.error(f"更新检查时间失败: {str(e)}")

        return False

    async def fetch_instagram_videos(self, db: Session, user: MonitoredUser, count: int, client_id: str = None):
        if client_id:
            await send_progress(client_id, {
                "type": "info",
                "message": f"正在获取Instagram用户 {user.username} 的视频列表"
            })

        # 获取视频方向设置
        orientation_setting = SystemSetting.get_value(db, "download_video_orientation", "both")
        logger.info(f"视频方向设置: {orientation_setting}")

        # 跟踪已处理的视频数量
        processed_count = 0
        # 所有有效视频
        all_valid_videos = []
        # 分页参数
        max_id = None
        # 每页的视频数
        page_size = 12  # Instagram API通常每页返回12个条目

        # 循环获取视频，直到达到目标数量或者没有更多视频
        while processed_count < count:
            # 请求视频列表，使用分页令牌
            response = await self.api_service.get_instagram_videos(user.user_id, count=page_size, max_id=max_id)

            if not response or response.get("code") != 200:
                logger.error(f"API请求错误或返回非200状态: {response}")
                if client_id:
                    await send_progress(client_id, {
                        "type": "warning",
                        "message": f"获取Instagram用户 {user.username} 的视频列表失败"
                    })
                break  # 出错时退出循环

            videos_data = response.get("data", {}).get("items", [])
            # 获取下一页的令牌（如果有）
            next_page_token = response.get("data", {}).get("paging_info", {}).get("max_id", None)
            has_more = response.get("data", {}).get("paging_info", {}).get("more_available", False)

            if not videos_data:
                logger.warn("未找到更多视频数据")
                if client_id:
                    await send_progress(client_id, {
                        "type": "info",
                        "message": f"未找到更多Instagram用户 {user.username} 的视频数据"
                    })
                break  # 没有更多视频，退出循环

            logger.info(f"获取到第 {max_id or '第一'} 页，找到 {len(videos_data)} 个条目")

            # 过滤出视频条目并保存到有效视频列表
            valid_videos = []
            for video_data in videos_data:
                media_data = video_data.get("media", {})
                if not media_data:
                    logger.warn(f"条目中缺少media字段: {video_data.keys()}")
                    continue

                video_id = media_data.get("pk", "")
                if not video_id:
                    logger.info("未找到视频ID，跳过")
                    continue

                # 检查是否是视频（而不是图片）
                is_video = media_data.get("is_video", False) or "video_versions" in media_data
                if not is_video:
                    logger.warn(f"条目 {video_id} 不是视频，跳过")
                    continue

                # 检查视频是否已存在
                existing_video = db.query(Video).filter(
                    Video.platform == "instagram",
                    Video.video_id == video_id
                ).first()

                if existing_video:
                    logger.warn(f"视频已存在，跳过: {video_id}")
                    continue

                valid_videos.append(video_data)

            # 将有效视频添加到总列表
            all_valid_videos.extend(valid_videos)
            processed_count += len(valid_videos)

            if client_id:
                await send_progress(client_id, {
                    "type": "info",
                    "message": f"找到Instagram用户 {user.username} 的 {len(valid_videos)} 个有效视频，总计 {processed_count} 个"
                })

            # 如果已经处理足够的视频或者没有更多页，退出循环
            if processed_count >= count or not has_more:
                break

            # 更新分页令牌，准备获取下一页
            max_id = next_page_token

            # 添加延迟，避免频繁请求API
            await asyncio.sleep(1)

        logger.info(f"共找到 {len(all_valid_videos)} 个有效视频")

        # 如果没有找到有效视频，则返回
        if not all_valid_videos:
            if client_id:
                await send_progress(client_id, {
                    "type": "warning",
                    "message": f"未找到Instagram用户 {user.username} 的有效视频"
                })
            return

        # 处理找到的有效视频（只处理需要的数量）
        videos_to_process = all_valid_videos[:count]
        for i, video_data in enumerate(videos_to_process):
            media_data = video_data.get("media", {})
            video_id = media_data.get("pk", "")

            if client_id:
                await send_progress(client_id, {
                    "type": "processing",
                    "message": f"处理Instagram视频 {i + 1}/{len(videos_to_process)}: {video_id}"
                })

            # 提取初始视频链接及其宽高信息
            original_url_list_with_info = extract_instagram_video_urls_with_info(video_data)
            logger.info(f"找到 {len(original_url_list_with_info)} 个原始视频链接")

            # 尝试通过单个视频API获取更高清晰度的链接
            hd_url_list_with_info = []

            try:
                logger.info(f"正在获取高清视频链接: {video_id}")
                if client_id:
                    await send_progress(client_id, {
                        "type": "info",
                        "message": f"正在获取Instagram视频 {video_id} 的高清链接"
                    })

                hd_video_response = await self.api_service.get_instagram_single_video(video_id)

                if hd_video_response and hd_video_response.get("code") == 200:
                    # 提取高清视频URL及其宽高信息
                    hd_url_list_with_info = extract_instagram_single_video_info(hd_video_response)

                    if hd_url_list_with_info:
                        logger.info(f"找到 {len(hd_url_list_with_info)} 个高清视频链接")

                        if client_id:
                            await send_progress(client_id, {
                                "type": "info",
                                "message": f"找到Instagram视频 {video_id} 的高清链接"
                            })
                    else:
                        logger.info("未找到高清视频链接")

            except Exception as e:
                if client_id:
                    await send_progress(client_id, {
                        "type": "warning",
                        "message": f"获取Instagram视频 {video_id} 高清链接时出错: {str(e)}"
                    })
                logger.error(f"获取高清视频链接时出错: {str(e)}")

            # 合并URL列表，高清链接优先，且避免重复
            all_urls_with_info = []
            seen_urls = set()

            # 先添加高清链接
            for url_info in hd_url_list_with_info:
                if url_info["url"] not in seen_urls:
                    all_urls_with_info.append(url_info)
                    seen_urls.add(url_info["url"])

            # 再添加原始链接（不重复的）
            for url_info in original_url_list_with_info:
                if url_info["url"] not in seen_urls:
                    all_urls_with_info.append(url_info)
                    seen_urls.add(url_info["url"])

            # 如果没有URL可用，记录错误并继续下一个
            if not all_urls_with_info:
                logger.warn(f"未找到任何可用的下载链接，跳过视频: {video_id}")
                if client_id:
                    await send_progress(client_id, {
                        "type": "warning",
                        "message": f"没有找到Instagram视频 {video_id} 的可用下载链接，跳过"
                    })
                continue

            logger.info(f"共获取到 {len(all_urls_with_info)} 个下载URL")

            # 在这里应用视频方向筛选
            filtered_urls, filter_info = filter_urls_by_orientation(all_urls_with_info, orientation_setting)
            logger.info(f"视频方向筛选结果: {filter_info}")

            # 如果筛选后没有可用的URL，跳过该视频
            if not filtered_urls:
                logger.info(f"视频 {video_id} 没有符合方向设置({orientation_setting})的链接，跳过")
                if client_id:
                    await send_progress(client_id, {
                        "type": "warning",
                        "message": f"视频 {video_id} 没有符合方向设置({orientation_setting})的链接，跳过"
                    })
                continue

            # 详细调试描述信息获取过程
            title = ""

            # 检查clips_metadata是否存在
            if "clips_metadata" in media_data:
                if "reusable_text_attribute_string" in media_data["clips_metadata"]:
                    title = media_data["clips_metadata"]["reusable_text_attribute_string"]

            # 如果描述仍为空且caption存在，尝试从caption获取
            if not title and "caption" in media_data:
                if media_data["caption"] is not None:  # 检查caption是否为None
                    if isinstance(media_data["caption"], dict) and "text" in media_data["caption"]:
                        title = media_data["caption"]["text"]

            # 如果描述仍为空，使用视频ID作为描述（兜底操作）
            if not title:
                title = f"Instagram视频_{video_id}"
                logger.warn(f"使用视频ID作为兜底标题: '{title}'")

            # 保存视频信息
            new_video = Video(
                user_id=user.id,
                platform="instagram",
                video_id=video_id,
                title=title,
                download_url=json.dumps(filtered_urls)  # 只保存筛选后的URL列表
            )

            db.add(new_video)
            db.commit()
            db.refresh(new_video)
            if client_id:
                await send_progress(client_id, {
                    "type": "info",
                    "message": f"Instagram视频 {video_id} 信息已保存到数据库，开始下载，共 {len(filtered_urls)} 个链接"
                })

            # 下载视频（使用筛选后的URL列表）
            logger.info(f"开始下载视频 {video_id}, 有 {len(filtered_urls)} 个可用链接")
            success = await self.download_video(db, new_video, filtered_urls, user.username, user.sequence_number,
                                                user.category, client_id)
            if success:
                await send_progress(client_id, {
                    "type": "success",
                    "message": f"instagram视频 {video_id} 下载成功"
                })
            else:
                await send_progress(client_id, {
                    "type": "error",
                    "message": f"Instagram视频 {video_id} 下载失败"
                })
            logger.info(f"视频下载结果: {'成功' if success else '失败'}")

    # 快手相关方法
    async def add_kuaishou_user_with_sequence(self, db: Session, sec_uid: str, sequence_number: str,
                                              category: str = None):
        try:
            # 检查用户是否已存在
            existing_user = db.query(MonitoredUser).filter(
                MonitoredUser.platform == "kuaishou",
                MonitoredUser.sec_uid == sec_uid
            ).first()

            if existing_user:
                # 如果需要，使用序列号和类别更新现有用户
                if sequence_number and not existing_user.sequence_number:
                    existing_user.sequence_number = sequence_number

                # 如果提供了新分类，且用户没有分类，则更新分类
                if category and not existing_user.category:
                    existing_user.category = category

                db.commit()
                logger.info(f"快手用户已存在: {existing_user.username}，跳过添加")
                return existing_user

            # 获取用户信息
            logger.info(f"开始获取快手用户信息: user_id={sec_uid}")
            response = await self.api_service.get_kuaishou_user(sec_uid)
            if not response:
                logger.error("获取快手用户信息失败: API返回空响应")
                return None

            if response.get("code") != 200:
                logger.error(f"获取快手用户信息失败: {response.get('message', '未知错误')}")
                return None

            user_data = response.get("data", {})
            if not user_data:
                logger.error(f"未找到快手用户数据: {response}")
                return None

            # 只保存相关的用户信息
            profile = user_data.get("userProfile", {}).get("profile", "")
            owner_count = user_data.get("userProfile", {}).get("ownerCount", {})
            username = profile.get("user_name", "")

            relevant_info = {
                "username": username,
                "user_id": profile.get("user_id", ""),
                "headurl": profile.get("headurl", ""),
                "user_text": profile.get("user_text", ""),
                "photo_public": owner_count.get("photo_public", 0),
                "sequence_number": sequence_number
            }

            # 创建新用户
            new_user = MonitoredUser(
                platform="kuaishou",
                username=username,
                sec_uid=sec_uid,
                user_id=profile.get("user_id", ""),
                profile_info=json.dumps(relevant_info),
                last_video_count=owner_count.get("photo_public", 0),
                category=category,  # 添加分类
                sequence_number=sequence_number
            )

            db.add(new_user)
            db.commit()
            db.refresh(new_user)

            logger.info(f"已添加快手用户: {username}, 视频数: {owner_count.get("photo_public", 0)}")
            return new_user
        except Exception as e:
            logger.error(f"添加快手用户出错: {str(e)}", exc_info=True)
            return None

    async def check_kuaishou_updates(self, db: Session, user: MonitoredUser, client_id: str = None):
        logger.info(f"检查快手用户更新: {user.username} (ID: {user.id})")

        if client_id:
            await send_progress(client_id, {
                "type": "info",
                "message": f"正在获取快手用户 {user.username} 的信息"
            })

        response = await self.api_service.get_kuaishou_user(user.user_id)
        if not response:
            logger.error(f"获取用户信息失败: {response}")
            if client_id:
                await send_progress(client_id, {
                    "type": "warning",
                    "message": f"获取快手用户 {user.username} 信息失败"
                })
            return False

        if response.get("code") != 200:
            logger.error(f"获取快手用户信息失败: {response.get('message', '未知错误')}")
            if client_id:
                await send_progress(client_id, {
                    "type": "warning",
                    "message": f"获取快手用户 {user.username} 信息失败"
                })
            return None

        user_data = response.get("data", {})

        if not user_data:
            logger.warn(f"未找到用户数据: {response}")
            if client_id:
                await send_progress(client_id, {
                    "type": "warning",
                    "message": f"未找到快手用户 {user.username} 的数据"
                })
            return False

        profile = user_data.get("userProfile", {}).get("profile", {})
        owner_count = user_data.get("userProfile", {}).get("ownerCount", {}).get("photo_public", 0)

        current_count = int(owner_count)  # 确保转换为整数
        last_count = int(user.last_video_count) if user.last_video_count else 0  # 确保转换为整数

        logger.info(f"用户 {user.username} - 当前视频数: {current_count}, 上次记录: {last_count} (ID: {user.id})")

        if client_id:
            await send_progress(client_id, {
                "type": "info",
                "message": f"快手用户 {user.username} 当前视频数: {current_count}, 上次记录: {last_count}"
            })

        if current_count > last_count:
            # 获取新视频
            new_count = current_count - last_count
            if client_id:
                await send_progress(client_id, {
                    "type": "update",
                    "message": f"发现快手用户 {user.username} 有 {new_count} 个新视频，开始获取"
                })
            logger.info(f"发现 {new_count} 个新视频，开始获取")
            await self.fetch_kuaishou_videos(db, user, new_count, client_id)

            # 只保存相关的用户信息
            try:
                existing_info = json.loads(user.profile_info) if user.profile_info else {}
            except:
                existing_info = {}

            relevant_info = {
                "username": user.username,
                "user_id": profile.get("user_id", existing_info.get("user_id", "")),
                "headurl": profile.get("headurl", existing_info.get("headurl", "")),
                "user_text": profile.get("user_text", existing_info.get("user_text", "")),
                "media_count": current_count
            }

            # 显式打印更新前后的值
            logger.info(f"更新用户 {user.username} - 视频数从 {user.last_video_count} 更新为 {current_count}")

            # 更新用户信息
            user.last_video_count = current_count
            user.profile_info = json.dumps(relevant_info)
            user.last_checked = get_local_time()

            try:
                db.commit()
                if client_id:
                    await send_progress(client_id, {
                        "type": "success",
                        "message": f"已更新快手用户 {user.username} 信息，新视频计数: {current_count}"
                    })
                logger.info(f"数据库更新成功 - 用户 {user.username} 新视频计数: {current_count}")
            except Exception as e:
                db.rollback()
                if client_id:
                    await send_progress(client_id, {
                        "type": "error",
                        "message": f"更新快手用户 {user.username} 信息失败: {str(e)}"
                    })
                logger.error(f"数据库更新失败: {str(e)}")
                return False

            # 验证更新是否成功
            db.refresh(user)
            logger.info(f"验证更新 - 用户 {user.username} 当前视频计数: {user.last_video_count}")

            return True

        # 只更新最后检查时间
        user.last_checked = get_local_time()
        try:
            db.commit()
            if client_id:
                await send_progress(client_id, {
                    "type": "info",
                    "message": f"快手用户 {user.username} 没有新视频，仅更新检查时间"
                })
            logger.warn("没有新视频，仅更新检查时间")
        except Exception as e:
            db.rollback()
            if client_id:
                await send_progress(client_id, {
                    "type": "error",
                    "message": f"更新快手用户 {user.username} 检查时间失败: {str(e)}"
                })
            logger.error(f"更新检查时间失败: {str(e)}")

        return False

    async def fetch_kuaishou_videos(self, db: Session, user: MonitoredUser, count: int, client_id: str = None):
        if client_id:
            await send_progress(client_id, {
                "type": "info",
                "message": f"正在获取快手用户 {user.username} 的视频列表"
            })

        # 获取视频方向设置
        orientation_setting = SystemSetting.get_value(db, "download_video_orientation", "both")
        logger.info(f"视频方向设置: {orientation_setting}")

        # 跟踪已处理的视频数量
        processed_count = 0
        # 所有有效视频
        all_valid_videos = []
        # 分页参数
        pcursor = None

        # 循环获取视频，直到达到目标数量或者没有更多视频
        while processed_count < count:
            # 请求视频列表，使用分页参数
            response = await self.api_service.get_kuaishou_videos(user.user_id, pcursor=pcursor)

            if not response or response.get("code") != 200:
                logger.error(f"API请求错误或返回非200状态: {response}")
                if client_id:
                    await send_progress(client_id, {
                        "type": "warning",
                        "message": f"获取快手用户 {user.username} 的视频列表失败"
                    })
                break  # 出错时退出循环

            videos_data = response.get("data", {}).get("feeds", [])
            # 获取下一页的令牌
            next_pcursor = response.get("data", {}).get("pcursor")

            # 检查是否有更多数据
            has_more = True
            if not next_pcursor or next_pcursor == "no_more":
                has_more = False

            if not videos_data:
                logger.warn("未找到更多视频数据")
                if client_id:
                    await send_progress(client_id, {
                        "type": "info",
                        "message": f"未找到更多快手用户 {user.username} 的视频数据"
                    })
                break  # 没有更多视频，退出循环

            logger.info(f"获取到第 {pcursor or '第一'} 页，找到 {len(videos_data)} 个条目")

            # 过滤并保存有效视频
            valid_videos = []
            for video_data in videos_data:
                # 检查是否有streamManifest字段和必要的视频信息
                if "streamManifest" not in video_data:
                    logger.warn("条目缺少streamManifest字段，跳过")
                    continue

                stream_manifest = video_data.get("streamManifest", {})
                video_id = stream_manifest.get("videoId", "")

                if not video_id:
                    logger.warn("未找到视频ID，跳过")
                    continue

                # 检查视频类型
                media_type = stream_manifest.get("mediaType", 0)
                if media_type != 2:  # 假设2表示视频
                    logger.warn(f"条目 {video_id} 不是视频 (mediaType={media_type})，跳过")
                    continue

                # 检查视频是否已存在
                existing_video = db.query(Video).filter(
                    Video.platform == "kuaishou",
                    Video.video_id == video_id
                ).first()

                if existing_video:
                    logger.warn(f"视频已存在，跳过: {video_id}")
                    continue

                valid_videos.append(video_data)

            # 将有效视频添加到总列表
            all_valid_videos.extend(valid_videos)
            processed_count += len(valid_videos)

            if client_id:
                await send_progress(client_id, {
                    "type": "info",
                    "message": f"找到快手用户 {user.username} 的 {len(valid_videos)} 个有效视频，总计 {processed_count} 个"
                })

            # 如果已经处理足够的视频或者没有更多页，退出循环
            if processed_count >= count or not has_more:
                break

            # 更新分页令牌，准备获取下一页
            pcursor = next_pcursor

            # 添加延迟，避免频繁请求API
            await asyncio.sleep(1)

        logger.info(f"共找到 {len(all_valid_videos)} 个有效视频")

        # 如果没有找到有效视频，则返回
        if not all_valid_videos:
            if client_id:
                await send_progress(client_id, {
                    "type": "warning",
                    "message": f"未找到快手用户 {user.username} 的有效视频"
                })
            return

        # 处理找到的有效视频（只处理需要的数量）
        videos_to_process = all_valid_videos[:count]
        for i, video_data in enumerate(videos_to_process):
            stream_manifest = video_data.get("streamManifest", {})
            video_id = stream_manifest.get("videoId", "")

            if client_id:
                await send_progress(client_id, {
                    "type": "processing",
                    "message": f"处理快手视频 {i + 1}/{len(videos_to_process)}: {video_id}"
                })

            # 提取视频URL及其宽高信息
            url_list_with_info = extract_kuaishou_video_urls_with_info(video_data)
            logger.info(f"找到 {len(url_list_with_info)} 个视频链接")

            # 如果没有URL可用，记录错误并继续下一个
            if not url_list_with_info:
                logger.warn(f"未找到视频下载URL，跳过: {video_id}")
                if client_id:
                    await send_progress(client_id, {
                        "type": "warning",
                        "message": f"没有找到快手视频 {video_id} 的可用下载链接，跳过"
                    })
                continue

            # 在这里应用视频方向筛选
            filtered_urls, filter_info = filter_urls_by_orientation(url_list_with_info, orientation_setting)
            logger.info(f"视频方向筛选结果: {filter_info}")

            # 如果筛选后没有可用的URL，跳过该视频
            if not filtered_urls:
                logger.info(f"视频 {video_id} 没有符合方向设置({orientation_setting})的链接，跳过")
                if client_id:
                    await send_progress(client_id, {
                        "type": "warning",
                        "message": f"视频 {video_id} 没有符合方向设置({orientation_setting})的链接，跳过"
                    })
                continue

            logger.info(f"共获取到 {len(filtered_urls)} 个下载URL")

            # 获取视频描述
            title = video_data.get("caption", "")
            if not title:
                title = f"快手视频_{video_id}"
                logger.warn(f"使用视频ID作为兜底标题: '{title}'")

            # 保存视频信息
            new_video = Video(
                user_id=user.id,
                platform="kuaishou",
                video_id=video_id,
                title=title,
                download_url=json.dumps(filtered_urls)  # 只保存筛选后的URL列表
            )

            db.add(new_video)
            db.commit()
            db.refresh(new_video)

            if client_id:
                await send_progress(client_id, {
                    "type": "info",
                    "message": f"快手视频 {video_id} 信息已保存到数据库，开始下载，共 {len(filtered_urls)} 个链接"
                })

            # 下载视频（使用筛选后的URL列表）
            logger.info(f"开始下载视频 {video_id}, 有 {len(filtered_urls)} 个可用链接")
            success = await self.download_video(db, new_video, filtered_urls, user.username, user.sequence_number,
                                                user.category, client_id)

            if success:
                await send_progress(client_id, {
                    "type": "success",
                    "message": f"快手视频 {video_id} 下载成功"
                })
            else:
                await send_progress(client_id, {
                    "type": "error",
                    "message": f"快手视频 {video_id} 下载失败"
                })

            logger.info(f"视频下载结果: {'成功' if success else '失败'}")

    # 通用方法
    async def download_video(self, db: Session, video: Video, url_list, username=None, user_sequence=None,
                             user_category=None, client_id: str = None):
        """
        下载视频

        参数:
            db: 数据库会话
            video: 视频对象
            url_list: URL列表或包含URL和宽高信息的列表
            username: 用户名
            user_sequence: 用户序列号
            user_category: 用户分类
            client_id: 客户端ID

        返回:
            bool: 下载是否成功
        """
        # 如果没有提供 db 参数，使用对象中存储的 db
        if db is None:
            db = self.db

        # 从系统设置获取配置参数
        if db is None:
            # 使用默认值
            max_retries = 3
            retry_delays = [2, 3, 4]
            timeout = 180
            min_delay = 1.0
            max_delay = 3.0
            logger.warn("警告: 数据库会话为空，使用默认配置值")
        else:
            # 从系统设置获取配置参数
            try:
                max_retries = int(SystemSetting.get_value(db, "max_retries", "3"))
                retry_delays_str = SystemSetting.get_value(db, "retry_delays", "2,3,4")
                retry_delays = [int(x) for x in retry_delays_str.split(",")]
                timeout = int(SystemSetting.get_value(db, "request_timeout", "180"))
                min_delay = float(SystemSetting.get_value(db, "min_delay", "1.0"))
                max_delay = float(SystemSetting.get_value(db, "max_delay", "3.0"))
            except Exception as e:
                logger.error(f"获取系统设置时出错: {str(e)}，使用默认值")
                max_retries = 3
                retry_delays = [2, 3, 4]
                timeout = 180
                min_delay = 1.0
                max_delay = 3.0

        # 在关键步骤添加进度通知
        if client_id:
            await send_progress(client_id, {
                "type": "downloading",
                "message": f"开始下载视频: {video.video_id}",
                "video": {
                    "id": video.id,
                    "platform": video.platform,
                    "video_id": video.video_id,
                    "title": video.title[:50] + "..." if len(
                        video.title) > 50 else video.title
                }
            })

        # 确保retry_delays列表长度与max_retries匹配
        while len(retry_delays) < max_retries:
            retry_delays.append(retry_delays[-1] * 2)  # 如果设置的延迟数量不足，添加额外的延迟值

        # 获取用户名/昵称、分类信息和序号
        if not username:
            # 如果没有传入用户名，尝试从数据库获取
            user = db.query(MonitoredUser).filter(MonitoredUser.id == video.user_id).first()
            if user:
                username = user.username
                user_category = user.category
                user_sequence = user.sequence_number
            else:
                username = "unknown_user"

        # 清理用户名，移除不适合作为文件夹名的特殊字符
        safe_username = get_safe_filename(username)

        # 如果有序号，将其添加到用户名后面，格式为: 用户名_序号
        if user_sequence:
            safe_username = f"{safe_username}_{user_sequence}"

        # 如果有分类，也做安全处理
        safe_category = ""
        if user_category:
            safe_category = get_safe_filename(user_category)

        # 获取今天的日期字符串，格式为YYYY-MM-DD
        today_date = datetime.datetime.now().strftime("%Y-%m-%d")

        # 获取日期文件夹设置（注意：这里的键应该是use_date_enabled，您写的是use_date_enable）
        use_date_enabled = SystemSetting.get_value(db, "use_date_enabled", "false").lower() == "true"

        # 创建目录结构，根据设置决定是否包含日期
        if safe_category:
            if use_date_enabled:
                # 如果启用了日期文件夹，则添加日期
                dir_path = os.path.join(self.download_dir, video.platform, safe_category, safe_username, today_date)
            else:
                # 未启用日期文件夹
                dir_path = os.path.join(self.download_dir, video.platform, safe_category, safe_username)
        else:
            if use_date_enabled:
                # 如果启用了日期文件夹，则添加日期
                dir_path = os.path.join(self.download_dir, video.platform, safe_username, today_date)
            else:
                # 未启用日期文件夹
                dir_path = os.path.join(self.download_dir, video.platform, safe_username)

        os.makedirs(dir_path, exist_ok=True)

        file_path = generate_filename(video.title, video.video_id, dir_path)

        logger.info(f"尝试下载视频到: {file_path}")
        if client_id:
            await send_progress(client_id, {
                "type": "info",
                "message": f"保存视频到: {file_path}"
            })

        logger.info(
            f"使用配置: 最大重试次数={max_retries}, 重试延迟={retry_delays}, 超时={timeout}秒, 随机延迟范围={min_delay}-{max_delay}秒")

        # 使用筛选后的URL列表
        if not url_list:
            logger.warn("过滤后的URL列表为空，无法下载")
            if hasattr(video, "download_status"):
                video.download_status = "failed"
            db.commit()
            return False

        success = False
        error_messages = []
        url_index = 0

        # 随机延迟函数，避免被识别为爬虫
        async def random_delay():
            delay = random.uniform(min_delay, max_delay)
            logger.info(f"添加随机延迟: {delay:.2f}秒")
            await asyncio.sleep(delay)

        # 使用过滤后的URL列表进行下载，以下是原有的下载逻辑
        for url in url_list:
            url_index += 1

            # 记录当前尝试的是高清还是标清URL
            url_quality = "高清" if url_index <= len(url_list) // 2 else "标清"
            logger.info(f"尝试下载 {url_quality} 视频 (URL {url_index}/{len(url_list)})")

            # 在每个URL尝试前添加随机延迟
            await random_delay()

            for retry in range(max_retries):
                try:
                    logger.info(f"尝试从URL下载: {url} (尝试 {retry + 1}/{max_retries})")

                    # 添加随机User-Agent，模拟不同浏览器
                    headers = {
                        'User-Agent': random.choice([
                            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
                            'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Safari/605.1.15',
                            'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0',
                            'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36',
                            'Mozilla/5.0 (iPhone; CPU iPhone OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1',

                            # PC端（桌面浏览器）
                            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36',
                            'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:115.0) Gecko/20100101 Firefox/115.0',
                            'Mozilla/5.0 (Macintosh; Intel Mac OS X 12_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Safari/605.1.15',
                            'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.6099.129 Safari/537.36',
                            'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Edge/18.19041',

                            # 移动端（手机和平板）
                            'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1',
                            'Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.6167.85 Mobile Safari/537.36',
                            'Mozilla/5.0 (Linux; Android 12; SM-G998B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Mobile Safari/537.36',
                            'Mozilla/5.0 (iPad; CPU OS 16_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Mobile/15E148 Safari/604.1',
                            'Mozilla/5.0 (Linux; Android 11; Redmi Note 10 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36'
                        ]),
                        'Accept': 'video/webm,video/mp4,video/*;q=0.9,*/*;q=0.8',
                        'Accept-Language': 'en-US,en;q=0.9',
                        'Accept-Encoding': 'gzip, deflate, br',
                        'Referer': 'https://www.google.com/',
                        'Connection': 'keep-alive',
                        'Cache-Control': 'max-age=0',
                        'Sec-Fetch-Dest': 'video',
                        'Sec-Fetch-Mode': 'no-cors',
                        'Sec-Fetch-Site': 'cross-site',
                        'Pragma': 'no-cache'
                    }

                    # 针对不同平台添加特定的请求头
                    if video.platform == "instagram":
                        headers.update({
                            'Origin': 'https://www.instagram.com',
                            'Referer': 'https://www.instagram.com/',
                        })
                    elif video.platform == "tiktok":
                        headers.update({
                            'Origin': 'https://www.tiktok.com',
                            'Referer': 'https://www.tiktok.com/',
                        })
                    elif video.platform == "douyin":
                        headers.update({
                            'Origin': 'https://www.douyin.com',
                            'Referer': 'https://www.douyin.com/',
                        })
                    elif video.platform == "kuaishou":
                        headers.update({
                            'Origin': 'https://www.kuaishou.com',
                            'Referer': 'https://www.kuaishou.com/',
                        })

                    async with aiohttp.ClientSession() as session:
                        async with session.get(url, headers=headers, timeout=timeout) as response:
                            if response.status == 200:
                                content = await response.read()
                                content_length = len(content)

                                if content_length < 1000:  # 检查内容是否太小，可能是错误页面
                                    logger.info(f"下载内容太小 ({content_length} 字节)，可能不是视频文件")
                                    error_messages.append(f"内容太小: {content_length} 字节")
                                    break  # 内容太小直接尝试下一个URL

                                # 检查内容类型是否为视频
                                content_type = response.headers.get('Content-Type', '')
                                if not ('video' in content_type or 'octet-stream' in content_type):
                                    logger.info(f"错误的内容类型: {content_type}，可能不是视频文件")
                                    error_messages.append(f"错误的内容类型: {content_type}")
                                    break  # 不是视频类型，尝试下一个URL

                                logger.info(f"下载完成，正在保存文件: {file_path}")
                                async with aiofiles.open(file_path, 'wb') as f:
                                    await f.write(content)

                                # 检查文件是否实际写入成功
                                if os.path.exists(file_path) and os.path.getsize(file_path) > 1000:
                                    logger.info(f"文件下载成功: {file_path} ({os.path.getsize(file_path)} 字节)")

                                    # 更新视频的本地路径，保存相对路径
                                    relative_path = os.path.relpath(file_path, os.path.join("app", "static"))
                                    video.local_path = f"/static/{relative_path}"
                                    if hasattr(video, "download_status"):
                                        video.download_status = "downloaded"
                                    if hasattr(video, "download_at"):
                                        video.download_at = get_local_time()

                                    # 记录下载品质信息
                                    video_quality = f"{url_quality} ({url_index}/{len(url_list)})"
                                    logger.info(f"成功下载 {video_quality} 视频")

                                    db.commit()

                                    success = True
                                    return True  # 下载成功直接返回
                                else:
                                    logger.error(f"文件下载失败或文件太小: {file_path}")
                                    error_messages.append("文件写入失败或文件太小")
                                    # 继续重试
                            elif response.status == 403:
                                logger.error(f"收到403 Forbidden响应，可能触发了速率限制，等待更长时间后重试")
                                error_messages.append(f"HTTP 403: 可能被限制")
                                # 对所有平台，403错误时统一使用更长的延迟
                                wait_time = retry_delays[retry] * 2
                                logger.info(f"等待 {wait_time} 秒...")
                                await asyncio.sleep(wait_time)
                            elif response.status == 429:
                                logger.error(f"收到429 Too Many Requests响应，等待更长时间后重试")
                                error_messages.append(f"HTTP 429: 请求过多")
                                # 对所有平台，429错误时统一使用更长的延迟
                                wait_time = retry_delays[retry] * 3
                                logger.info(f"等待 {wait_time} 秒...")
                                await asyncio.sleep(wait_time)
                            else:
                                logger.error(f"HTTP响应错误: {response.status} {response.reason}")
                                error_messages.append(f"HTTP {response.status}: {response.reason}")
                                # 其他错误使用标准延迟
                                if retry < max_retries - 1:  # 如果不是最后一次重试
                                    wait_time = retry_delays[retry]
                                    logger.info(f"等待 {wait_time} 秒后重试...")
                                    await asyncio.sleep(wait_time)

                    # 如果没有捕获异常但也没有成功，可能是其他问题，继续尝试下一个URL
                    if not success:
                        await send_progress(client_id, {
                            "type": "error",
                            "message": f"当前URL下载未成功，尝试下一个URL"
                        })
                        logger.error("当前URL下载未成功，尝试下一个URL")
                        break

                except aiohttp.ClientError as e:
                    logger.error(f"请求错误: {str(e)} (尝试 {retry + 1}/{max_retries})")
                    error_messages.append(f"请求错误: {str(e)}")
                    if retry < max_retries - 1:  # 如果不是最后一次重试
                        wait_time = retry_delays[retry]
                        logger.info(f"等待 {wait_time} 秒后重试...")
                        await asyncio.sleep(wait_time)
                except asyncio.TimeoutError:
                    logger.error(f"请求超时 (尝试 {retry + 1}/{max_retries})")
                    error_messages.append("请求超时")
                    if retry < max_retries - 1:  # 如果不是最后一次重试
                        wait_time = retry_delays[retry]
                        logger.info(f"等待 {wait_time} 秒后重试...")
                        await asyncio.sleep(wait_time)
                except Exception as e:
                    logger.error(f"下载时发生未知错误: {str(e)} (尝试 {retry + 1}/{max_retries})")
                    error_messages.append(f"未知错误: {str(e)}")
                    if retry < max_retries - 1:  # 如果不是最后一次重试
                        wait_time = retry_delays[retry]
                        logger.info(f"等待 {wait_time} 秒后重试...")
                        await asyncio.sleep(wait_time)

        if success:
            if client_id:
                await send_progress(client_id, {
                    "type": "success",
                    "message": f"视频 {video.video_id} 下载成功: {file_path}",
                    "file_path": video.local_path
                })
            return True
        else:
            logger.error(f"所有下载尝试都失败: {error_messages}")

            # 保存最后使用的URL，用于手动下载
            if url_list and len(url_list) > 0:
                if hasattr(video, "last_download_url"):
                    video.last_download_url = url_list[0]  # 保存第一个URL

            # 计算下次重试时间
            retry_interval = int(SystemSetting.get_value(db, "failed_download_retry_interval", "14400"))
            next_retry = get_local_time() + datetime.timedelta(seconds=retry_interval)

            # 更新视频状态
            if hasattr(video, "download_status"):
                video.download_status = "failed"
            if hasattr(video, "next_retry_at"):
                video.next_retry_at = next_retry
            if hasattr(video, "local_path"):
                video.local_path = None
            db.commit()

            logger.info(f"视频下载失败，已安排重试: {video.video_id}, 下次重试时间: {next_retry}")

            if client_id:
                await send_progress(client_id, {
                    "type": "error",
                    "message": f"所有下载尝试都失败，已安排重试: {video.video_id}, 下次重试时间: {next_retry}"
                })
            return False
